Loading

主席树模板

应用场景

静态: 查询区间第K大

动态: 带修改的查询区间第K大

静态

P3834【模板】可持久化线段树 1(主席树)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define clr(a, x) memset(a, x, sizeof(a))
 4 #define rep(i,a,n) for(int i=a;i<=n;i++)
 5 #define pre(i,a,n) for(int i=a;i>=n;i--)
 6 #define ll long long
 7 const double eps = 1e-6;
 8 const int INF = 0x3f3f3f3f;
 9 const int mod = 1e9 + 7;
10 const int N = 2e5+20;
11 int a[N],b[N],T[N],L[N*20],R[N*20],sum[N*20];
12 int tot = 0,n,q,x,y,z,m;
13 
14 int Build(int l,int r)
15 {
16     int rt = ++tot;
17     int mid = (l+r)>>1;
18     if(l < r)
19     {
20         L[rt] = Build(l,mid);
21         R[rt] = Build(mid+1,r);
22     }
23     return rt;
24 }
25 
26 int update(int pre,int l,int r,int x)
27 {
28     int rt = ++tot;
29     int mid = (l+r)>>1;
30     L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre]+1;
31     if(l < r)
32     {
33         if(x <= mid)
34             L[rt] = update(L[pre],l,mid,x);
35         else 
36             R[rt] = update(R[pre],mid+1,r,x);
37     }
38     return rt;
39 }
40 
41 int query(int u,int v,int l,int r,int k)
42 {
43     if(l == r)
44         return l;
45     int mid = (l+r)>>1;
46     int x = sum[L[v]]-sum[L[u]];
47     if(x >= k)
48         return query(L[u],L[v],l,mid,k);
49     else 
50         return query(R[u],R[v],mid+1,r,k-x);
51 }
52 
53 int main()
54 {
55     tot = 0;
56     clr(T,0);   clr(sum,0); clr(L,0);   clr(R,0);   clr(a,0);   clr(b,0);
57     scanf("%d %d",&n,&q);
58     rep(i,1,n)
59     {
60         scanf("%d",&a[i]);
61         b[i] = a[i];
62     }   
63     sort(b+1,b+1+n);
64     m = unique(b+1,b+1+n)-b-1;
65     T[0] = Build(1,m);
66     rep(i,1,n)
67     {
68         a[i] = lower_bound(b+1,b+1+m,a[i])-b;
69         T[i] = update(T[i-1],1,m,a[i]);
70     }
71     rep(i,1,q)
72     {
73         scanf("%d %d %d",&x,&y,&z);
74         int p = query(T[x-1],T[y],1,m,z);
75         printf("%d\n",b[p]);
76     }
77     return 0;
78 }

动态

P2617 Dynamic Rankings

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define clr(a, x) memset(a, x, sizeof(a))
  4 #define rep(i,a,n) for(int i=a;i<=n;i++)
  5 #define pre(i,a,n) for(int i=n;i>=a;i--)
  6 #define ll long long
  7 #define lowbit(a) a&(-a)
  8 const int N = 200050;
  9 
 10 int cnt,siz,dot,idx;
 11 // 内存分配的下标,不同数值点的个数,总共的点数,修改操作的下标
 12 int root[N],cpy[N],data[N];
 13 // 静态主席树的根节点,离散化后的数据,原始数据
 14 int vir[N],use[N];
 15 // 树状数组的节点,计算前缀和时向前走的节点
 16 
 17 // 因为主席树必须离线,所以将指令存下来
 18 struct order
 19 {
 20     bool typ;   // biaoji查询还是修改
 21     int from,to,k;
 22 }command[N];
 23 
 24 struct node
 25 {int son[2],sum;}tree[N*250];
 26 // 内存一定要开的足够大,因为在这里静态主席树和树状数组共用这个数组内的点
 27 
 28 int build(int l,int r)   // 建立空树 类似线段树
 29 {
 30     int now = cnt++;
 31     tree[cnt].sum = 0;
 32     if(l != r)
 33     {
 34         int mid = (l+r)>>1;
 35         tree[now].son[0] = build(l,mid);
 36         tree[now].son[1] = build(mid+1,r);
 37     }
 38     return now;
 39 }
 40 
 41 int updata(int last,int pos,int val)   // 更新虚拟节点或者插入静态主席树的函数
 42 // 为了方便删除,传入val代表修改的量
 43 {
 44     int now = cnt++,tmp = now,mid;
 45     int l = 0,r = siz-1;   // 保存的是离散化后的对应的值的编号
 46     tree[now].sum = tree[last].sum+val;
 47     while(l < r)
 48     {
 49         mid = (l+r)>>1;
 50         if(pos <= mid)   // 待插入节点在左子树
 51         {
 52             tree[now].son[1] = tree[last].son[1];
 53             // 那么当前节点的右子树节点和之前的那棵权值线段树共用节点
 54             tree[now].son[0] = cnt++;   // 向左新开一个节点
 55             now  = tree[now].son[0];
 56             last = tree[last].son[0];
 57             r = mid;
 58         }
 59         else            // 待插入节点在右子树 
 60         {
 61             tree[now].son[0] = tree[last].son[0];
 62             tree[now].son[1] = cnt++;
 63             now  = tree[now].son[1];
 64             last = tree[last].son[1];
 65             l = mid+1;
 66         }
 67         tree[now].sum = tree[last].sum+val;
 68     }
 69     return tmp;
 70 }
 71 
 72 void add(int now,int pos,int val)
 73 {
 74     while(now <= dot)
 75     {
 76         vir[now] = updata(vir[now],pos,val);
 77         now += lowbit(now);
 78     }
 79 }
 80 
 81 int getsum(int now)   // 查询当前点更改值的左子树的大小
 82 {
 83     int ret = 0;
 84     while(now > 0)
 85     {
 86         ret += tree[tree[use[now]].son[0]].sum;
 87         now -= lowbit(now);
 88     }
 89     return ret;
 90 }
 91 
 92 int query(int l,int r,int kth)
 93 {
 94     int left_root  = root[l-1];  // 静态主席树的两个相减的根节点
 95     int right_root = root[r];
 96     int lef = 0,rig = siz-1;     // 查询时左右范围
 97     for(int i = l-1;i;i -= lowbit(i))  use[i] = vir[i];
 98     // 初始化更改值的路径
 99     for(int i = r;i;i -= lowbit(i))    use[i] = vir[i];
100     while(lef < rig)
101     {
102         int mid = (lef+rig)>>1;
103         int now_sum = getsum(r)-getsum(l-1)+tree[tree[right_root].son[0]].sum-tree[tree[left_root].son[0]].sum;
104         // 查询当前点的左儿子是否满足达到了k个
105         // 在静态主席树和树状数组上一起算
106         if(now_sum >= kth)   // 达到了
107         {
108             rig = mid;
109             for(int i = l-1;i;i -= lowbit(i))   use[i] = tree[use[i]].son[0];
110             // 将查询范围缩小至左子树内
111             for(int i = r;i;i -= lowbit(i))     use[i] = tree[use[i]].son[0];
112             left_root  = tree[left_root].son[0];   // 同时静态主席树也要如此
113             right_root = tree[right_root].son[0];
114         }
115         else   // 没达到就在右子树范围内继续查找 
116         {
117             lef = mid+1;
118             kth -= now_sum;   // 因为有了左子树的一部分点,所以要减去
119             for(int i = l-1;i;i -= lowbit(i))   use[i] = tree[use[i]].son[1];
120             for(int i = r;i;i -= lowbit(i))     use[i] = tree[use[i]].son[1];
121             left_root  = tree[left_root].son[1];
122             right_root = tree[right_root].son[1];
123         }
124     }
125     return lef;   // 返回是第几个离散出来的数据
126 }
127 
128 int id(int now)
129 {
130     return lower_bound(cpy,cpy+siz,now)-cpy;
131 }
132 
133 int main()
134 {
135     int num;
136     scanf("%d %d",&dot,&num);
137     idx = dot;
138     for(int i = 1;i <= dot;i++)
139     {
140         scanf("%d",&data[i]);
141         cpy[i-1] = data[i];   // cpy从0开始存方便unique和sort
142     }
143     char c[10];
144     for(int i = 1;i <= num;i++)
145     {
146         scanf("%s",c);
147         if(c[0] == 'Q')
148         {
149             command[i].typ = false;
150             scanf("%d %d %d",&command[i].from,&command[i].to,&command[i].k);
151         }
152         else 
153         {
154             command[i].typ = true;
155             scanf("%d %d",&command[i].from,&command[i].k);
156             cpy[idx++] = command[i].k;   // 如果是修改的话存入cpy中
157         }
158     }
159     sort(cpy,cpy+idx);
160     siz = unique(cpy,cpy+idx)-cpy;
161     root[0] = build(0,siz-1);    // 建立空静态主席树
162     for(int i = 1;i <= dot;i++)
163         root[i] = updata(root[i-1],id(data[i]),1);   // 建立满的静态主席树
164     for(int i = 1;i <= dot;++i)
165         vir[i] = root[0];         // 初始化树状数组
166     for(int i = 1;i <= num;i++)   // 处理指令
167     {
168         if(!command[i].typ)
169           printf("%d\n",cpy[query(command[i].from,command[i].to,command[i].k)]);
170         else 
171         {
172             add(command[i].from,id(data[command[i].from]),-1);
173             add(command[i].from,id(command[i].k),1);
174             data[command[i].from] = command[i].k;   // 将原数据修改至新数据
175         }
176     }
177     return 0;
178 }

 

posted @ 2021-01-20 20:55  Yiduuannng  阅读(89)  评论(0编辑  收藏  举报