标签:
题意:对于一段区间,每次求[l,r]的第k大,存在单点修改操作;
思路:
学习主席树参考:
http://blog.csdn.net/wjf_wzzc/article/details/24560117(各种形式)
http://blog.csdn.net/bossup/article/details/31921235(推荐)
http://blog.csdn.net/xiaofengcanyuexj/article/details/25553521?utm_source=tuicool(图解)
http://blog.csdn.net/metalseed/article/details/8045038(原理)
--------------------------------------------
主席树是一种可持久化的线段树,支持历史版本查询,区间不同数的个数查询,区间第k大查询等动态操作;
由很多棵线段树组成的树,每棵子树记录包含数字的个数,相当于维护不同的区间;单独线段树无法求不同区间的第k大,而主席树可以;
开始时先建一棵空树,作为原始版本;每次更新(插入一个数)时都尽量利用历史版本,即节省空间,又提高了效率;并采用了二分的思想;
询问时,通过二分枚举最优值,与两端点对应的树的左子树的差值(即为该数在[l,r]中的个数)比较,分治到左右区间中查询;
---------------------------------------------
本题使用树状数组维护动态树的前缀和,降低复杂度,查询时再将数在动态树与静态树中出现次数并起来一起比较;
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=60010; const int M=2500010; int n,q,m,tot; int a[maxn],t[maxn]; int T[maxn],lson[M],rson[M],c[M]; int S[maxn]; int used[maxn]; struct node{ int kind; int l,r,k; }query[10010]; void Init_hash(int k) { sort(t,t+k); m=unique(t,t+k)-t; } int hash(int x) { return lower_bound(t,t+m,x)-t; } int build(int l,int r){ int root=tot++; c[root]=0; if(l!=r){ int mid=(l+r)/2; lson[root]=build(l,mid); rson[root]=build(mid+1,r); } return root; } int Insert(int root,int pos,int val) { int newroot=tot++,tmp=newroot; int l=0,r=m-1; c[newroot]=c[root]+val; while(l<r) { int mid=(l+r)/2; if(pos<=mid){ lson[newroot]=tot++;rson[newroot]=rson[root]; newroot=lson[newroot];root=lson[root]; r=mid; } else{ rson[newroot]=tot++;lson[newroot]=lson[root]; newroot=rson[newroot];root=rson[root]; l=mid+1; } c[newroot]=c[root]+val; } return tmp; } int lowbit(int x){ return x&(-x); } /*void add(int x,int pos,int val){ while(x<=n){ S[x]=Insert(S[x],pos,val); x+=lowbit(x); } }*/ int sum(int x){ int ret=0; while(x>0){ ret+=c[lson[used[x]]]; x-=lowbit(x); } return ret; } int Query(int left,int right,int k){ int left_root=T[left-1]; int right_root=T[right]; int l=0,r=m-1; for(int i=left-1;i;i-=lowbit(i)) used[i]=S[i]; for(int i=right;i;i-=lowbit(i)) used[i]=S[i]; while(l<r){ int mid=(l+r)/2; int tmp=sum(right)-sum(left-1)+c[lson[right_root]]-c[lson[left_root]]; if(tmp>=k){ r=mid; for(int i=left-1;i;i-=lowbit(i)) used[i]=lson[used[i]]; for(int i=right;i;i-=lowbit(i)) used[i]=lson[used[i]]; left_root=lson[left_root]; right_root=lson[right_root]; } else{ l=mid+1; k-=tmp; for(int i=left-1;i;i-=lowbit(i)) used[i]=rson[used[i]]; for(int i=right;i;i-=lowbit(i)) used[i]=rson[used[i]]; left_root=rson[left_root]; right_root=rson[right_root]; } } return l; } void modify(int x,int p,int d){ while(x<=n){ S[x]=Insert(S[x],p,d); x+=lowbit(x); } } int main() { int Tcase; scanf("%d",&Tcase); while(Tcase--){ scanf("%d%d",&n,&q); tot=0; m=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); t[m++]=a[i]; } char op[10]; for(int i=0;i<q;i++){ scanf("%s",op); if(op[0]==‘Q‘){ query[i].kind=0; scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k); } else{ query[i].kind=1; scanf("%d%d",&query[i].l,&query[i].r); t[m++]=query[i].r; } } Init_hash(m); //离散化,使树的数量尽量小 T[0]=build(0,m-1); //建一棵树,有编号,但节点数量为0 for(int i=1;i<=n;i++) T[i]=Insert(T[i-1],hash(a[i]),1); for(int i=1;i<=n;i++) S[i]=T[0]; for(int i=0;i<q;i++){ if(query[i].kind==0){ printf("%d\n",t[Query(query[i].l,query[i].r,query[i].k)]); } else{ modify(query[i].l,hash(a[query[i].l]),-1); modify(query[i].l,hash(query[i].r),1); a[query[i].l]=query[i].r; } } } return 0; }
zoj 2112 Dynamic Rankings(树状数组套主席树)
标签:
原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4740139.html