题解:P12179 DerrickLo's Game (UBC002B)
首先,每次询问,操作后的序列显然是原序列中的最大值。比这个值大显然不会更优秀。
然后区间赋最大值显然是两个两个赋值比一大段的赋值更优秀,因为
所以每个数赋值成最大值代价最多是 4。
考虑什么情况下代价小于 4,显然是这个数和最大值的差距小于 4。
现在我们可以把询问的序列中的数分成和最大值差距大于等于 4 和小于等于 4 的来考虑。
考虑如何快速计算小于等于 4 的个数,可以对每个值开一颗权值线段树,这样可以快速查询一个区间中某个数的出现次数。
然后查询最大值再开一颗线段树即可。
#include<bits/stdc++.h>
#define ll long long
#define reg register
#define db double
#define il inline
using namespace std;
void read(int &x){x=0;int f=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}x*=f;}
void read(ll &x){x=0;int f=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}x*=f;}
const int N=2e5+5;
int n,q,a[N];
struct node{
int tree[N*4];
void push_up(int x){
tree[x]=max(tree[x<<1],tree[x<<1|1]);
}
void build(int x,int l,int r){
if(l==r)tree[x]=a[l];
else {
int mid=(l+r)/2;build(x<<1,l,mid);build(x<<1|1,mid+1,r);
push_up(x);
}
}
void update(int x,int l,int r,int q){
if(l==r)tree[x]=a[l];
else {
int mid=(l+r)/2;
if(q<=mid)update(x<<1,l,mid,q);
else update(x<<1|1,mid+1,r,q);
push_up(x);
}
}
int query(int x,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return tree[x];
int re=0,mid=(l+r)/2;
if(ql<=mid)re=query(x<<1,l,mid,ql,qr);
if(qr>mid)re=max(re,query(x<<1|1,mid+1,r,ql,qr));
return re;
}
}T;
int tree[N*50],ls[N*50],rs[N*50],tot;
int rt[N];
il void push_up(int x){
tree[x]=tree[ls[x]]+tree[rs[x]];
}
void update(int x,int l,int r,int q,int w){
if(l==r){
tree[x]+=w;return ;
}int mid=(l+r)/2;
if(q<=mid){
if(ls[x]==0)ls[x]=++tot;
update(ls[x],l,mid,q,w);
}else{
if(rs[x]==0)rs[x]=++tot;
update(rs[x],mid+1,r,q,w);
}
push_up(x);
}
int query(int x,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return tree[x];
int re=0,mid=(l+r)/2;
if(ql<=mid&&ls[x])re=query(ls[x],l,mid,ql,qr);
if(qr>mid&&rs[x])re+=query(rs[x],mid+1,r,ql,qr);
return re;
}
int main(){
read(n);read(q);
for(int i=1;i<=200000;i++){
rt[i]=++tot;
}
for(int i=1;i<=n;i++){
read(a[i]);
update(rt[a[i]],1,n,i,1);
}
T.build(1,1,n);
while(q--){
int op,l,r;
read(op);read(l);read(r);
if(op==1){
update(rt[a[l]],1,n,l,-1);
a[l]=r;
update(rt[a[l]],1,n,l,1);
T.update(1,1,n,l);
}else{
int tmp=T.query(1,1,n,l,r),cnt=0,cnt2=0,ans=0;
for(int i=tmp;i>=max(1,tmp-3);i--){
cnt2=query(rt[i],1,n,l,r);
ans+=(tmp-i)*cnt2;
cnt+=cnt2;
}
ans+=(r-l+1-cnt)*4;
printf("%d\n",ans);
}
}
return 0;
}