I Think
题意:求数列区间第k大+修改操作
算法:静态主席树+动态修改主席树(树状数组区间修改区间查询)
思路:理解了主席树和树状数组在某种意义上都存储前缀和的共同性质就好。
实现:Insert函数是非递归实现,还要注意到在树状数组中修改后,原数组a[]也需要更新。
Code
代码参考大神:http://blog.csdn.net/u014664226/article/details/47839973
#include<cstdio>
#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
using namespace std;
//zoj 2112 静态主席树+动态修改主席树
const int sm = 6e4+1000;
const int sn = 2400000;
int n,m,cs,cnt,tot,f;
int a[sm],t[sm],T[sm],S[sm];
int ls[sn],rs[sn],c[sn],use[sm];
struct query {
int ind,l,r,k;
}q[50000+10];
char ch;
void read(int &x) {
x=0,f=1,ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
x*=f;
}
int hash(int x) { return lower_bound(t+1,t+cnt+1,x)-t; }
void Build(int &rt,int l,int r) {
rt=++tot,c[rt]=0;
if(l==r) return;
int m=(l+r)>>1;
Build(ls[rt],l,m);
Build(rs[rt],m+1,r);
}
int Insert(int pre,int p,int val) {
int RT=++tot;
int rt=RT,l=1,r=cnt,m;
c[rt]=c[pre]+val;
while(l<r) {
m=(l+r)>>1;
if(p<=m) {
rs[rt]=rs[pre],ls[rt]=++tot;
pre=ls[pre],rt=ls[rt],r=m;
}
else {
ls[rt]=ls[pre],rs[rt]=++tot;
pre=rs[pre],rt=rs[rt],l=m+1;
}
c[rt]=c[pre]+val;
}
return RT;
}
void Modify(int x,int p,int val) {
for(int i=x;i<=n;i+=lowbit(i))
S[i]=Insert(S[i],p,val);
}
int Sum(int x) {
int ret=0;
for(int i=x;i;i-=lowbit(i))
ret+=c[ls[use[i]]];
return ret;
}
int Query(int L,int R,int k) {
int lft=T[--L],rgt=T[R],l=1,r=cnt,mid,tmp;
for(int i=L;i;i-=lowbit(i)) use[i]=S[i];
for(int i=R;i;i-=lowbit(i)) use[i]=S[i];
while(l<r) {
mid=(l+r)>>1;
tmp=c[ls[rgt]]-c[ls[lft]]+Sum(R)-Sum(L); //静态主席树上的差量+树状数组上的差量
if(tmp>=k) {
r=mid,lft=ls[lft],rgt=ls[rgt];
for(int i=L;i;i-=lowbit(i)) use[i]=ls[use[i]]; //use[i]也相应向下一层
for(int i=R;i;i-=lowbit(i)) use[i]=ls[use[i]];
}
else {
l=mid+1,k-=tmp,lft=rs[lft],rgt=rs[rgt];
for(int i=L;i;i-=lowbit(i)) use[i]=rs[use[i]];
for(int i=R;i;i-=lowbit(i)) use[i]=rs[use[i]];
}
}
return l;
}
int main() {
read(cs);
while(cs--) {
read(n),read(m),tot=0,cnt=0;
for(int i=1;i<=n;++i)
read(a[i]),t[++cnt]=a[i];
for(int i=1;i<=m;++i) {
ch=getchar();
if(ch=='C') {
read(q[i].l),read(q[i].k);
q[i].ind=2,t[++cnt]=q[i].k;
}
else {
read(q[i].l),read(q[i].r);
q[i].ind=1,read(q[i].k);
}
}
sort(t+1,t+cnt+1);
cnt=unique(t+1,t+cnt+1)-t-1;
Build(T[0],1,cnt);
for(int i=1;i<=n;++i)
T[i]=Insert(T[i-1],hash(a[i]),1),S[i]=T[0];//?
for(int i=1;i<=m;++i) {
if(q[i].ind==1)
printf("%d\n",t[Query(q[i].l,q[i].r,q[i].k)]);
else {
Modify(q[i].l,hash(a[q[i].l]),-1);
Modify(q[i].l,hash(q[i].k),1);
a[q[i].l]=q[i].k;//下次再改动该点值需要调用modify
}
}
}
return 0;
}