主席树初探--BZOJ1901: Zju2112 Dynamic Rankings
n<=10000的序列做m<=10000个操作:单点修改,查区间第k小。
所谓的主席树也就是一个值域线段树嘛。。不过在这里还是%%fotile
需要做一个区间查询,由于查第k小,需要一些能够支持数值操作的东西,那就选择值域线段树,线段树上每个区间[L,R]表示的是值在L~R的数的相关信息,比如这里的“有多少个”。
不过呢这样的线段树没法维护区间下标怎么求区间信息啊,那就BIT套线段树,BIT上每个点表示一段区间(lowbit)的数值之和。为了空间,先离散化再动态开点效果拔群。
然后单点修改就该logn棵线段树,区间查询[L,R]就把R和L-1两个前缀的信息来相减。
这里第一次写树套树,见识了一种好操作!因为要同时操作很多棵线段树并且要在里面走来走去,就开一些指针一起走。那怎么知道谁要走呢?每次要区间查询时先init一下,把设计的线段树标记出来。由于两个前缀相减可能会有一些树标记到两次,那在前缀相减完之后这些标记两次的相当于不用算了,所以就把他们标记清除即可。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 //#include<iostream> 6 using namespace std; 7 8 int n,m; 9 #define maxn 20011 10 #define maxm 4000011 11 12 struct SMT 13 { 14 struct Node 15 { 16 int son[2]; 17 int l,r; 18 int cnt; 19 }a[maxm]; 20 int size,n; 21 void clear(int m) {n=m;size=0;a[0].cnt=0;} 22 void up(int x) {a[x].cnt=a[a[x].son[0]].cnt+a[a[x].son[1]].cnt;} 23 void insert(int &x,int L,int R,int num) 24 { 25 if (!x) {x=++size;a[x].l=L;a[x].r=R;a[x].cnt=1;} 26 else a[x].cnt++; 27 if (L==R) return; 28 const int mid=(L+R)>>1; 29 if (num<=mid) insert(a[x].son[0],L,mid,num); 30 else insert(a[x].son[1],mid+1,R,num); 31 } 32 void insert(int &x,int num) {insert(x,1,n,num);} 33 void Delete(int &x,int L,int R,int num) 34 { 35 a[x].cnt--; 36 if (!a[x].cnt) {x=0;return;} 37 if (L==R) return; 38 const int mid=(L+R)>>1; 39 if (num<=mid) Delete(a[x].son[0],L,mid,num); 40 else Delete(a[x].son[1],mid+1,R,num); 41 } 42 void Delete(int &x,int num) {Delete(x,1,n,num);} 43 }smt; 44 struct BIT 45 { 46 int a[maxn],t[maxn],n; 47 int vis[maxn]; 48 void clear(int m) {n=m;memset(a,0,sizeof(a));memset(vis,0,sizeof(vis));} 49 void add(int x,int num) {for (;x<=n;x+=x&-x) smt.insert(a[x],num);} 50 void minus(int x,int num) {for (;x<=n;x+=x&-x) smt.Delete(a[x],num);} 51 void init(int x,int Time) 52 {for (;x;x-=x&-x) if (vis[x]!=Time) vis[x]=Time,t[x]=a[x];else vis[x]=0;} 53 int query(int x,int Time) 54 {int ans=0;for (;x;x-=x&-x) if (vis[x]==Time) ans+=smt.a[smt.a[t[x]].son[0]].cnt;return ans;} 55 void turn(int x,int Time,int dir) {for (;x;x-=x&-x) if (vis[x]==Time) t[x]=smt.a[t[x]].son[dir];} 56 }t; 57 58 struct Doo 59 { 60 bool type;int x,y,z; 61 }doo[maxn]; 62 int lisan[maxn],a[maxn],li=0; 63 int main() 64 { 65 scanf("%d%d",&n,&m); 66 for (int i=1;i<=n;i++) scanf("%d",&a[i]),lisan[++li]=a[i]; 67 for (int i=1;i<=m;i++) 68 { 69 char c=' ';while (c!='Q' && c!='C') c=getchar(); 70 if ((doo[i].type=(c=='Q'))) scanf("%d%d%d",&doo[i].x,&doo[i].y,&doo[i].z); 71 else scanf("%d%d",&doo[i].x,&doo[i].y),lisan[++li]=doo[i].y; 72 } 73 sort(lisan+1,lisan+1+li);li=unique(lisan+1,lisan+1+li)-lisan-1; 74 for (int i=1;i<=n;i++) a[i]=lower_bound(lisan+1,lisan+1+li,a[i])-lisan; 75 for (int i=1;i<=m;i++) if (!doo[i].type) doo[i].y=lower_bound(lisan+1,lisan+1+li,doo[i].y)-lisan; 76 77 t.clear(n);smt.clear(li); 78 for (int i=1;i<=n;i++) t.add(i,a[i]); 79 for (int i=1;i<=m;i++) 80 { 81 if (doo[i].type) 82 { 83 int x=doo[i].x-1,y=doo[i].y,z=doo[i].z,l=1,r=li,tmp; 84 t.init(y,i);t.init(x,i); 85 while (l<r) 86 { 87 if ((tmp=t.query(y,i)-t.query(x,i))>=z) r=(l+r)>>1,t.turn(y,i,0),t.turn(x,i,0); 88 else l=((l+r)>>1)+1,z-=tmp,t.turn(y,i,1),t.turn(x,i,1); 89 } 90 printf("%d\n",lisan[l]); 91 } 92 else 93 { 94 t.minus(doo[i].x,a[doo[i].x]); 95 t.add(doo[i].x,(a[doo[i].x]=doo[i].y)); 96 } 97 } 98 return 0; 99 }