版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/90319217
题目:BZOJ1901.
题目大意:给定一个长度为
的序列
,支持
次操作:
1.格式
,表示查询区间
中第
大的数.
2.格式
,表示把
改成
.
.
POJ2104的拓展.
由于现在有了真正的修改操作,所以考虑把修改拆成两个,一个是把原来这个位置上的数的贡献撤销,一个是给这个位置上加入新数的贡献.
具体实现可以看代码.
时间复杂度 .
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=10000,INF=1000000000;
char rc(){
char c=getchar();
for (;c<'A'||c>'Z';c=getchar());
return c;
}
int n,m,c[N+9],a[N+9];
void Add(int p,int v){if (!p) return;for (;p<=n;p+=p&-p) c[p]+=v;}
int Query(int p){int res=0;for (;p;p-=p&-p) res+=c[p];return res;}
int Query(int l,int r){return Query(r)-Query(l-1);}
struct question{
int opt,x,y,z,id;
question(int Opt=0,int X=0,int Y=0,int Z=0,int Id=0){opt=Opt;x=X;y=Y;z=Z;id=Id;}
}q[N*3+9],lq[N*3+9],rq[N*3+9];
int cq,ans[N+9];
void Divide(question *q,int L,int R,int h,int t){
if (h>t) return;
if (L==R){
for (int i=h;i<=t;++i)
if (!q[i].opt) ans[q[i].id]=L;
return;
}
int mid=L+R>>1,lt=0,rt=0,tmp;
for (int i=h;i<=t;++i)
if (q[i].opt){
if (q[i].y>mid) rq[++rt]=q[i];
else Add(q[i].x,q[i].z),lq[++lt]=q[i];
}else{
tmp=Query(q[i].x,q[i].y);
if (q[i].z<=tmp) lq[++lt]=q[i];
else q[i].z-=tmp,rq[++rt]=q[i];
}
for (int i=h;i<=t;++i)
if (q[i].opt&&q[i].y<=mid) Add(q[i].x,-q[i].z);
for (int i=1;i<=lt;++i) q[h+i-1]=lq[i];
for (int i=1;i<=rt;++i) q[h+lt+i-1]=rq[i];
Divide(q,L,mid,h,h+lt-1);
Divide(q,mid+1,R,h+lt,t);
}
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i){
scanf("%d",&a[i]);
q[++cq]=question(1,i,a[i],1,0);
}
char opt;
int x,y,z;
for (int i=1;i<=m;++i){
opt=rc();
if (opt=='C'){
scanf("%d%d",&x,&y);
q[++cq]=question(1,x,a[x],-1,0);
q[++cq]=question(1,x,y,1,0);
a[x]=y;
}else{
scanf("%d%d%d",&x,&y,&z);
q[++cq]=question(0,x,y,z,i);
}
ans[i]=-1;
}
}
Abigail work(){
Divide(q,0,INF,1,cq);
}
Abigail outo(){
for (int i=1;i<=m;++i)
if (ans[i]^-1) printf("%d\n",ans[i]);
}
int main(){
into();
work();
outo();
return 0;
}