BZOJ_1901_&_ZJU_2112_Dynamic_Rankings_(主席树+树状数组/线段树+(Treap/Splay))
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1901
给出一个长度为n的数列A,有m次询问,询问分两种:1.修改某一位置的值;2.求区间[l,r]内的第k小的值.
1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6716 Solved: 2793
[Submit][Status][Discuss]
Description
给 定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在 a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对 改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令, 你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示 a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Input
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Output
Sample Input
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
6
HINT
20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。
Source
分析
对于只有第一种询问的问题: POJ_2104_Kth(主席树)
现在要求动态.我们思考这样一个问题:把求区间第k小的问题变成求区间和值的问题,这个好解决吧?对于静态的问题,我们使用前缀和即可解决,那么对于动态的呢?使用树状数组维护前缀和.那么现在把问题变回求区间第k小值的问题.对于静态的问题,我们还是使用前缀和的思想,不过这一次每个前缀和不再是代表[1,i]的和值,而是[1,i]的一棵线段树,然后找到区间左右断点,相减即可得到答案.者可以理解为"前缀和套线段树",并且我们使用可持久化的思想大大减小空间开销.那么对于动态的问题,我们还是使用树状数组的思想,不过这一次每个点不再代表[i-lowbit(i)+1,i]的和值,而是代表[i-lowbit[i]+1,i]的一棵线段树.问题就迎刃而解了.
注意:
1.这里的每一个点代表的主席树刚开始都是由root[i](=0)建立的,之后修改的时候已有的就不需要再建立了.由于主席树的空间需求不好估计(对于这样的问题,空间的上界是(n+m)(logn*logn),但实际上远远用不到),虽然也可以写成每次修改无论之前有没有都直接复制一份,但是在空间不确定的情况下,写成前一种不容易爆炸.
前一种:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn=10000+5; 6 struct node{ int l,r,s; }t[maxn*400]; 7 struct qry{ int a,b,c; }q[maxn]; 8 int n,m,cnt,tot,num; 9 int a[maxn],b[maxn<<1],root[maxn],L[maxn],R[maxn]; 10 11 inline int lowbit(int x){ return x&(-x); } 12 void update(int l,int r,int &pos,int d,int s){ 13 if(!pos)t[++cnt]=t[pos], pos=cnt; 14 t[pos].s+=s; 15 if(l==r) return; 16 int mid=(l+r)/2; 17 if(d<=mid) update(l,mid,t[pos].l,d,s); 18 else update(mid+1,r,t[pos].r,d,s); 19 } 20 void change(int x,int d,int s){ for(;x<=n;x+=lowbit(x)) update(1,num,root[x],d,s); } 21 int query(int l,int r,int k,int cl,int cr){ 22 if(l==r) return l; 23 int suml=0,sumr=0; 24 for(int i=1;i<=cl;i++) suml+=t[t[L[i]].l].s; 25 for(int i=1;i<=cr;i++) sumr+=t[t[R[i]].l].s; 26 int s=sumr-suml,mid=(l+r)/2; 27 if(k<=s){ 28 for(int i=1;i<=cl;i++) L[i]=t[L[i]].l; 29 for(int i=1;i<=cr;i++) R[i]=t[R[i]].l; 30 return query(l,mid,k,cl,cr); 31 } 32 else{ 33 for(int i=1;i<=cl;i++) L[i]=t[L[i]].r; 34 for(int i=1;i<=cr;i++) R[i]=t[R[i]].r; 35 return query(mid+1,r,k-s,cl,cr); 36 } 37 } 38 int get_ans(int l,int r,int k){ 39 int cl,cr; 40 for(cl=0;l>0;l-=lowbit(l)) L[++cl]=root[l]; 41 for(cr=0;r>0;r-=lowbit(r)) R[++cr]=root[r]; 42 return query(1,num,k,cl,cr); 43 } 44 int main(){ 45 scanf("%d%d",&n,&m); 46 char c; 47 for(int i=1;i<=n;i++) scanf("%d",&a[i]), b[++tot]=a[i]; 48 for(int i=1;i<=m;i++){ 49 for(c=getchar();c<'A'||c>'Z';c=getchar()); 50 scanf("%d%d",&q[i].a,&q[i].b); 51 if(c=='Q') scanf("%d",&q[i].c); 52 else b[++tot]=q[i].b; 53 } 54 sort(b+1,b+1+tot); 55 b[tot+1]=0x7fffffff; 56 for(int i=1;i<=tot;i++) if(b[i]!=b[i+1]) b[++num]=b[i]; 57 for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+num,a[i])-b; 58 for(int i=1;i<=n;i++) change(i,a[i],1); 59 for(int i=1;i<=m;i++){ 60 if(q[i].c) printf("%d\n",b[get_ans(q[i].a-1,q[i].b,q[i].c)]); 61 else{ 62 change(q[i].a,a[q[i].a],-1); 63 a[q[i].a]=lower_bound(b+1,b+1+num,q[i].b)-b; 64 change(q[i].a,a[q[i].a],1); 65 } 66 } 67 return 0; 68 } 69 70 前一种
后一种:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn=10000+5; 6 struct node{ int l,r,s; }t[maxn*400]; 7 struct qry{ int a,b,c; }q[maxn]; 8 int n,m,cnt,tot,num; 9 int a[maxn],b[maxn<<1],root[maxn],L[maxn],R[maxn]; 10 11 inline int lowbit(int x){ return x&(-x); } 12 void update(int l,int r,int &pos,int d,int s){ 13 t[++cnt]=t[pos]; t[cnt].s+=s; pos=cnt; 14 if(l==r) return; 15 int mid=(l+r)/2; 16 if(d<=mid) update(l,mid,t[pos].l,d,s); 17 else update(mid+1,r,t[pos].r,d,s); 18 } 19 void change(int x,int d,int s){ for(;x<=n;x+=lowbit(x)) update(1,num,root[x],d,s); } 20 int query(int l,int r,int k,int cl,int cr){ 21 if(l==r) return l; 22 int suml=0,sumr=0; 23 for(int i=1;i<=cl;i++) suml+=t[t[L[i]].l].s; 24 for(int i=1;i<=cr;i++) sumr+=t[t[R[i]].l].s; 25 int s=sumr-suml,mid=(l+r)/2; 26 if(k<=s){ 27 for(int i=1;i<=cl;i++) L[i]=t[L[i]].l; 28 for(int i=1;i<=cr;i++) R[i]=t[R[i]].l; 29 return query(l,mid,k,cl,cr); 30 } 31 else{ 32 for(int i=1;i<=cl;i++) L[i]=t[L[i]].r; 33 for(int i=1;i<=cr;i++) R[i]=t[R[i]].r; 34 return query(mid+1,r,k-s,cl,cr); 35 } 36 } 37 int get_ans(int l,int r,int k){ 38 int cl,cr; 39 for(cl=0;l>0;l-=lowbit(l)) L[++cl]=root[l]; 40 for(cr=0;r>0;r-=lowbit(r)) R[++cr]=root[r]; 41 return query(1,num,k,cl,cr); 42 } 43 int main(){ 44 scanf("%d%d",&n,&m); 45 char c; 46 for(int i=1;i<=n;i++) scanf("%d",&a[i]), b[++tot]=a[i]; 47 for(int i=1;i<=m;i++){ 48 for(c=getchar();c<'A'||c>'Z';c=getchar()); 49 scanf("%d%d",&q[i].a,&q[i].b); 50 if(c=='Q') scanf("%d",&q[i].c); 51 else b[++tot]=q[i].b; 52 } 53 sort(b+1,b+1+tot); 54 b[tot+1]=0x7fffffff; 55 for(int i=1;i<=tot;i++) if(b[i]!=b[i+1]) b[++num]=b[i]; 56 for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+num,a[i])-b; 57 for(int i=1;i<=n;i++) change(i,a[i],1); 58 for(int i=1;i<=m;i++){ 59 if(q[i].c) printf("%d\n",b[get_ans(q[i].a-1,q[i].b,q[i].c)]); 60 else{ 61 change(q[i].a,a[q[i].a],-1); 62 a[q[i].a]=lower_bound(b+1,b+1+num,q[i].b)-b; 63 change(q[i].a,a[q[i].a],1); 64 } 65 } 66 return 0; 67 }
p.s.这题可以用线段树套平衡树做(貌似树状数组套平衡树也是可以的?树状数组不太熟啊...)
线段树+Treap:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn=10000+5,oo=~0u>>1; 7 int n,q; 8 int a[maxn]; 9 char str[3]; 10 struct Treap{ 11 struct node{ 12 node* ch[2]; 13 int v,r,s,c; 14 node(int v,node* t):v(v){ ch[0]=ch[1]=t; r=rand(); s=c=1; } 15 void push_up(){ s=ch[0]->s+ch[1]->s+c; } 16 }*root,*null; 17 Treap(){ 18 null=new node(0,NULL); 19 null->c=null->s=0; null->r=oo; 20 root=null; 21 } 22 void rotate(node* &o,bool d){ 23 node* k=o->ch[!d]; o->ch[!d]=k->ch[d]; k->ch[d]=o; 24 o->push_up(); k->push_up(); o=k; 25 } 26 void insert(node* &o,int x){ 27 if(o==null) o=new node(x,null); 28 else{ 29 if(x==o->v) o->s++, o->c++; 30 else{ 31 bool d=x>o->v; 32 insert(o->ch[d],x); 33 if(o->ch[d]->r<o->r) rotate(o,!d); 34 o->push_up(); 35 } 36 } 37 } 38 void remove(node* &o,int x){ 39 if(o->v==x){ 40 if(o->c>1) o->c--, o->s--; 41 else{ 42 if(o->ch[0]!=null&&o->ch[1]!=null){ 43 bool d=o->ch[0]->r<o->ch[1]->r; 44 rotate(o,d); remove(o->ch[d],x); o->push_up(); 45 } 46 else{ 47 node* u=o; 48 o=o->ch[0]==null?o->ch[1]:o->ch[0]; 49 delete u; 50 } 51 } 52 } 53 else{ 54 bool d=x>o->v; 55 remove(o->ch[d],x); 56 o->push_up(); 57 } 58 } 59 int rank(int x){ 60 int ret=0; 61 for(node* t=root;t!=null;){ 62 int s=t->ch[0]->s+t->c; 63 if(x>t->v) ret+=s, t=t->ch[1]; 64 else t=t->ch[0]; 65 } 66 return ret; 67 } 68 int pre(int x){ 69 int ret=-oo; 70 for(node* t=root;t!=null;){ 71 if(t->v<x) ret=t->v, t=t->ch[1]; 72 else t=t->ch[0]; 73 } 74 return ret; 75 } 76 }; 77 struct Segment_Tree{ 78 Treap tree[maxn*4]; 79 void build_tree(int l,int r,int k){ 80 for(int i=l;i<=r;i++) tree[k].insert(tree[k].root,a[i]); 81 if(l==r) return; 82 int mid=l+(r-l)/2; 83 build_tree(l,mid,k<<1); build_tree(mid+1,r,k<<1|1); 84 } 85 int get_rank(int l,int r,int k,int x,int y,int X){ 86 if(l==x&&r==y) return tree[k].rank(X); 87 int mid=l+(r-l)/2; 88 if(y<=mid) return get_rank(l,mid,k<<1,x,y,X); 89 else if(x>mid) return get_rank(mid+1,r,k<<1|1,x,y,X); 90 else return get_rank(l,mid,k<<1,x,mid,X)+get_rank(mid+1,r,k<<1|1,mid+1,y,X); 91 } 92 void change(int l,int r,int k,int id,int x){ 93 tree[k].remove(tree[k].root,a[id]); 94 tree[k].insert(tree[k].root,x); 95 if(l==r) return; 96 int mid=l+(r-l)/2; 97 if(id<=mid) change(l,mid,k<<1,id,x); 98 else change(mid+1,r,k<<1|1,id,x); 99 } 100 int get_pre(int l,int r,int k,int x,int y,int X){ 101 if(l==x&&r==y) return tree[k].pre(X); 102 int mid=l+(r-l)/2; 103 if(y<=mid) return get_pre(l,mid,k<<1,x,y,X); 104 else if(x>mid) return get_pre(mid+1,r,k<<1|1,x,y,X); 105 else return max(get_pre(l,mid,k<<1,x,mid,X),get_pre(mid+1,r,k<<1|1,mid+1,y,X)); 106 } 107 int get_kth(int x,int y,int k){ 108 long long l=-oo,r=oo; 109 while(l<r){ 110 int mid=(int)(l+(r-l)/2); 111 int tmp=get_rank(1,n,1,x,y,mid)+1; 112 if(tmp<=k) l=mid+1; 113 else r=mid; 114 } 115 return get_pre(1,n,1,x,y,l); 116 } 117 }T; 118 119 int main(){ 120 scanf("%d%d",&n,&q); 121 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 122 T.build_tree(1,n,1); 123 for(int i=1;i<=q;i++){ 124 scanf("%s",str); 125 int l,r,k,id,x; 126 if(str[0]=='Q'){ 127 scanf("%d%d%d",&l,&r,&k); 128 printf("%d\n",T.get_kth(l,r,k)); 129 } 130 else{ 131 scanf("%d%d",&id,&x); 132 T.change(1,n,1,id,x); 133 a[id]=x; 134 } 135 } 136 return 0; 137 }