Solution P12179 DerrickLo's Game (UBC002B)
诈骗题。
首先发现两个操作都不会把数变小,因此最后一定是把区间内所有数变成区间最大值。
然后考虑操作二代价是平方,所以发现选的区间越长反而代价越大。例如长度为 \(a\ (a\ge3)\) 的区间,原来需要花费 \(a^2=(a-1+1)^2=(a-1)^2+2a-1\) 的代价,将其拆成长度为 \(2\) 和 \(a-1\) 的区间(并大小为 \(1\)),则代价为 \(4+(a-1)^2<2a-1+(a-1)^2\)。
那么发现操作二等价于每次选择一个长度为 \(2\) 的区间,花费代价 \(4\)。进一步发现由于操作顺序可以任意排列,因此操作二等价于选择一个数花费 \(4\) 的代价变成整个区间的最大值。
那么就可以做了:考虑暴力找出区间内分别有多少个值与最大值相差小于 \(4\) 的数,这些数做操作一,剩下的做操作二。找区间内多少个等于 \(v\) 的数直接使用动态开点线段树维护即可。时间复杂度 \(O(n\log n)\)。
const int N=200005,M=10000005;
int n,q,a[N];
struct SegT{
int rt[N],cnt[M],lc[M],rc[M],tot=0;
il void add(int &x,int l,int r,int p,int v){
if(!x)x=++tot;if(l==r)return cnt[x]+=v,void();int mid=(l+r)>>1;
p<=mid?add(lc[x],l,mid,p,v):add(rc[x],mid+1,r,p,v),cnt[x]=cnt[lc[x]]+cnt[rc[x]];
}
il int qry(int x,int l,int r,int bg,int ed){
if(!x)return 0;else if(bg<=l&&r<=ed)return cnt[x];int mid=(l+r)>>1,a=0;
if(bg<=mid)a=qry(lc[x],l,mid,bg,ed);if(mid<ed)a+=qry(rc[x],mid+1,r,bg,ed);return a;
}
}ds;
struct MX{
int mx[N*4];
il void upd(int x,int l,int r,int p,int v){
if(l==r)return mx[x]=v,void();int mid=(l+r)>>1;
p<=mid?upd(x<<1,l,mid,p,v):upd(x<<1|1,mid+1,r,p,v),mx[x]=max(mx[x<<1],mx[x<<1|1]);
}
il int qry(int x,int l,int r,int bg,int ed){
if(bg<=l&&r<=ed)return mx[x];int mid=(l+r)>>1,a=0;
if(bg<=mid)a=qry(x<<1,l,mid,bg,ed);if(mid<ed)a=max(a,qry(x<<1|1,mid+1,r,bg,ed));return a;
}
}mx;
signed main(){
n=read(),q=read();
forto(i,1,n)a[i]=read(),ds.add(ds.rt[a[i]],1,n,i,1),mx.upd(1,1,n,i,a[i]);
int op,l,r;
while(q--){
op=read(),l=read(),r=read();
if(op==1){
ds.add(ds.rt[a[l]],1,n,l,-1),a[l]=r,ds.add(ds.rt[a[l]],1,n,l,1);
mx.upd(1,1,n,l,r);
}else{
int x=mx.qry(1,1,n,l,r),c=r-l+1,ans=0;
forbk(v,x,max(x-4,1)){
int cnt=ds.qry(ds.rt[v],1,n,l,r);
c-=cnt,ans+=cnt*(x-v);
}
ans+=4*c;
printf("%d\n",ans);
}
}
return 0;
}