LGP12179 DerrickLo's Game 学习笔记
LGP12179 DerrickLo's Game 学习笔记
题意简述
给定一个长为 \(n\) 的序列 \(A\)。\(q\) 次操作:
1 k x将 \(a_k\) 变为 \(x\)。2 l r问仅通过以下行为使区间 \([l,r]\) 变为相同的数所需要花费的最小代价。
“以下行为”指:
- 选择一个 \(a_p\) 使其单点加 \(1\),代价为 \(1\)。
- 选择一个整数区间 \([l,r]\) 使其中的数都变为区间最大值。代价 \((r-l+1)^2\)。
\(1\le n,q,a_i\le 2\times 10^5\)。
做法解析
这道题目的 \((r-l+1)^2\) 是吓人用的。因为 \(a,b>0\) 时显然有 \((a+b)^2>a^2+b^2\),所以你发现你用 \(2\) 行为操作的区间长度最长为 \(2\)。实际上这相当于可以花费 \(4\) 的代价将某个数变为最大值。
这样我们就只关心哪些数的代价小于 \(4\) 了。显然就是和最大值差小于 \(4\) 的。这个信息可以线段树维护。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=2e5+5;
int N,Q,A[MaxN],Opt,X,Y;
int aaa=max(1,2);
struct SegTree{
int ls(int u){return u<<1;}
int rs(int u){return (u<<1)|1;}
struct node{
int mx,d[4];
node(){mx=0,memset(d,0,sizeof(d));}
friend bool operator<(node &a,node &b){return a.mx<b.mx;}
friend node operator+(node a,node b){
if(a<b)swap(a,b);
int diff=a.mx-b.mx;if(diff>=4)return a;
for(int i=0,j=diff;j<4;i++,j++)a.d[j]+=b.d[i];
return a;
}
friend node& operator+=(node &a,const node &b){a=a+b;return a;}
}t[MaxN<<2];
void pushup(int u){t[u]=t[ls(u)]+t[rs(u)];}
void doleaf(int u,int x){t[u].mx=x,t[u].d[0]=1;}
void build(int u,int cl,int cr){
if(cl==cr){doleaf(u,A[cl]);return;}int cmid=(cl+cr)>>1;
build(ls(u),cl,cmid),build(rs(u),cmid+1,cr),pushup(u);
}
void update(int u,int cl,int cr,int dd,int x){
if(cl==cr){doleaf(u,x);return;}int cmid=(cl+cr)>>1;
dd<=cmid?update(ls(u),cl,cmid,dd,x):update(rs(u),cmid+1,cr,dd,x);
pushup(u);
}
node getans(int u,int cl,int cr,int dl,int dr){
if(dl<=cl&&cr<=dr)return t[u];
int cmid=(cl+cr)>>1;node res;
if(dl<=cmid)res+=getans(ls(u),cl,cmid,dl,dr);
if(dr>cmid)res+=getans(rs(u),cmid+1,cr,dl,dr);
return res;
}
}SgT;
int main(){
readis(N,Q);
for(int i=1;i<=N;i++)readi(A[i]);
SgT.build(1,1,N);
for(int i=1,ans,sd;i<=Q;i++){
readis(Opt,X,Y);
if(Opt==1)SgT.update(1,1,N,X,Y);
if(Opt==2){
ans=sd=0;auto [cmx,cd]=SgT.getans(1,1,N,X,Y);
for(int i=0;i<4;i++)ans+=i*cd[i],sd+=cd[i];
ans+=4*((Y-X+1)-sd);writil(ans);
}
}
return 0;
}
浙公网安备 33010602011771号