主席树初探--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 }
View Code

 

posted @ 2017-11-29 16:18  Blue233333  阅读(...)  评论(...编辑  收藏