题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112
静态的主席树用于记录静态的未修改的序列的贡献(板子)
对于单点修改来说,修改id处的数字相当于将该棵主席树以及在此基础上的主席树都修改掉,那么单次修改的复杂度就会达到n*log(n),而这个操作就相当于区间修改吧,那么最适合做区间修改,单点查询的是什么
树状数组啊
在这里的这颗树状数组的每个节点都是一颗权值线段树,如果每次修改我们都新建一颗权值线段树,空间扛不住啊,于是我们可以将每次修改的部分新建,不受影响的部分直接划等号拉过来就可以。
显然这种操作需要将所有操作离线才可。
将id的值修改为x,就相当于我们先把权值线段树中原来id的值对应的位置减一,再把x对应的位置加一。
最开始的时候还没有进行修改,那么可以新建一颗权值全部为空的权值线段树,树状数组所有的点都连到这颗树上,之后进行修改在自身的基础上搞一搞就可以了。
这里的树状数组与主席树没有直接联系!可以说这是两块东西分别维护需要维护的东西。
这道题多推敲,一定要想一想树里面的东西到底是什么
参考博客:https://blog.csdn.net/u014664226/article/details/47839973
https://blog.csdn.net/creatorx/article/details/75581617
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+7;
const int maxm=1e4+7;
int m;
int tot;
int a[maxn],b[maxn+maxm];
struct Tree{
int sum;
int lc,rc;
}tree[2136839];
int root[maxn];
void out(){
cout<<(int)(maxn*4+maxn*log2(maxn)+maxm*log2(maxn))<<endl;
}
void init(int n){
tot=0;
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
}
int getid(int x){
return lower_bound(b+1,b+1+m,x)-b;
}
int build(int l,int r){
int k=++tot;
tree[k].sum=0;
if(l==r) return k;
int mid=(l+r)>>1;
tree[k].lc=build(l,mid);
tree[k].rc=build(mid+1,r);
return k;
}
int updata(int p,int l,int r,int id,int val){
int k=++tot;
tree[k]=tree[p];
if(l==r){
tree[k].sum+=val;
return k;
}
int mid=(l+r)>>1;
if(id<=mid) tree[k].lc=updata(tree[p].lc,l,mid,id,val);
else tree[k].rc=updata(tree[p].rc,mid+1,r,id,val);
tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
return k;
}
int S[maxn];//树状数组中线段树的最开始的节点;
int X[maxn],Y[maxn];//树状数组中该次查找会用到的线段树的节点编号;
int n;
int lowbit(int x){
return x&(-x);
}
void add(int x,int id,int val){
for(;x<=n;x+=lowbit(x))
S[x]=updata(S[x],1,m,id,val);
}
int getsum(int x,int a[]){
int res=0;
for(;x;x-=lowbit(x))
res+=tree[tree[a[x]].lc].sum;
return res;
}
//区间查询非递归写法;
int myfind(int p,int q,int k){
int l=1,r=m,mid;
int left_root=root[q-1],right_root=root[p];
for(int x=p;x;x-=lowbit(x)) Y[x]=S[x];
for(int x=q-1;x;x-=lowbit(x)) X[x]=S[x];
while(l<r){
mid=(l+r)>>1;
int summ=getsum(p,Y)-getsum(q-1,X)+tree[tree[right_root].lc].sum-tree[tree[left_root].lc].sum;
if(k<=summ){
r=mid;
for(int x=p;x;x-=lowbit(x)) Y[x]=tree[Y[x]].lc;
for(int x=q-1;x;x-=lowbit(x)) X[x]=tree[X[x]].lc;
left_root=tree[left_root].lc;
right_root=tree[right_root].lc;
}
else{
k-=summ;
l=mid+1;
for(int x=p;x;x-=lowbit(x)) Y[x]=tree[Y[x]].rc;
for(int x=q-1;x;x-=lowbit(x)) X[x]=tree[X[x]].rc;
left_root=tree[left_root].rc;
right_root=tree[right_root].rc;
}
}
return l;
}
struct Node{
int l,r;
int k;
bool f;
}qq[maxm];
char s[9];
int main(){
//out();
int t,q;
scanf("%d",&t);
while(t--){
int len=0;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
b[++len]=a[i];
}
for(int i=1;i<=q;++i){
scanf("%s",s);
if(s[0]=='Q'){
scanf("%d%d%d",&qq[i].l,&qq[i].r,&qq[i].k);
qq[i].f=1;
}
else{
scanf("%d%d",&qq[i].l,&qq[i].r);
qq[i].f=0;
b[++len]=qq[i].r;
}
}
init(len);
//cout<<m<<endl;
root[0]=build(1,m);
for(int i=1;i<=n;++i) root[i]=updata(root[i-1],1,m,getid(a[i]),1);
for(int i=1;i<=n;++i) S[i]=root[0];
for(int i=1;i<=q;++i){
if(qq[i].f) printf("%d\n",b[myfind(qq[i].r,qq[i].l,qq[i].k)]);
else{
add(qq[i].l,getid(a[qq[i].l]),-1);
add(qq[i].l,getid(qq[i].r),1);
a[qq[i].l]=qq[i].r;
}
}
}
return 0;
}