主席树+可修改主席树

普通主席树


普通主席树比较简单 就是很多个权值线段树 每一次加进去log个节点(每层一个),剩下的节点用原来的线段树中的节点直接连到新节点上就好了

线段树

插入节点

主席树

主席树拆开之后

POJ2104 主席树模板题 代码:

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<vector>
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 ll read(){
 8     ll x=0,f=1;char c=getchar();
 9     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
10     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
11     return x*f;
12 }
13 
14 const int maxn=100100,maxm=5050;
15 int n,m,cnt,nums;
16 int a[maxn],b[maxn],num[maxn],root[maxn];
17 vector<int> vec;
18 struct Node{
19     int l,r,val;
20 } tr[maxn*40];
21 
22 int getid(int x){return int(lower_bound(vec.begin(),vec.end(),x)-vec.begin())+1;}
23 
24 void update(int l,int r,int &x,int y,int val){
25     nums++;tr[nums]=tr[y];tr[nums].val++;x=nums;
26     if(l==r) return;
27     int md=(l+r)>>1;
28     if(val<=md) update(l,md,tr[x].l,tr[y].l,val);
29     else update(md+1,r,tr[x].r,tr[y].r,val);
30 }
31 int ask(int l,int r,int x,int y,int val){
32     if(l==r) return l;
33     int md=(l+r)>>1;
34     int nw=tr[tr[y].l].val-tr[tr[x].l].val;
35     if(val<=nw) return ask(l,md,tr[x].l,tr[y].l,val);
36     else return ask(md+1,r,tr[x].r,tr[y].r,val-nw);
37 }
38 
39 int main(){
40     #ifdef LZT
41     //freopen("in","r",stdin);
42     #endif
43     n=read(),m=read();
44     for(int i=1;i<=n;i++)
45         a[i]=read(),vec.push_back(a[i]);
46     sort(vec.begin(),vec.end());vec.erase(unique(vec.begin(),vec.end()),vec.end());
47     for(int i=1;i<=n;i++)
48         a[i]=getid(a[i]),update(1,n,root[i],root[i-1],a[i]);
49     for(int i=1;i<=m;i++){
50         int l=read(),r=read(),k=read();
51         printf("%d\n",vec[ask(1,n,root[l-1],root[r],k)-1]);
52     }
53     return 0;
54 }j
55 
56 /*
57 7 3
58 1 5 2 6 3 7 4
59 2 5 3
60 4 4 1
61 1 7 3
62 */
poj2104

 

可修改主席树 


其实就是树状数组套主席树

为什么不能直接修改呢?

因为主席树的第i棵树是被第i+1到n棵树包含的

那么每次修改就得把后面的所有的树全部修改一遍

如果运气不好 复杂度可能达到$O(mn \log n)

那么我们需要一个每个点可以通过log的时间算出来并且修改也只需log的时间的东西----->树状数组

ZOJ2112 Dynamic Rankings

这是一道可修改主席树的模板题

目前并没有看出来这个数据结构有什么应用 但是感觉很有用的样子

好像也可以cdq分治+整体二分做

这题比较卡内存 所以初值单独记录在一个线段树中 修改记录在树状数组中 查询的时候综合一下

时间复杂度: $O(M× \log n× \log n+n \log n)$

代码:

  1 //#pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include<iostream>
  3 #include<stdio.h>
  4 #include<math.h>
  5 #include <string>
  6 #include<string.h>
  7 #include<map>
  8 #include<queue>
  9 #include<set>
 10 #include<utility>
 11 #include<vector>
 12 #include<algorithm>
 13 #include<stdlib.h>
 14 using namespace std;
 15 #define eps 1e-8
 16 #define pii pair<int,int>
 17 #define inf 0x3f3f3f3f
 18 #define rd(x) scanf("%d",&x)
 19 #define rd2(x,y) scanf("%d%d",&x,&y)
 20 #define ll long long int
 21 #define mod 1000000007
 22 #define maxn 60005
 23 #define maxm 2500005
 24 int m,n,nn,tot;
 25 int a[maxn],f[maxn],T[maxn],S[maxn];
 26 int sum[maxm],l[maxm],r[maxm];
 27 int use[maxn];
 28 int h(int x){//该值在离散化后线段树的位置
 29     return lower_bound(f+1,f+1+nn,x)-f;
 30 }
 31 void update(int pr,int lx,int rx,int v,int k){//插入,即新建第i个线段树
 32     l[++tot]=l[pr];r[tot]=r[pr];sum[tot]=sum[pr]+k;
 33     if(lx==rx) return;
 34     int mid=(lx+rx)>>1;
 35     if(v<=mid) {
 36             l[tot]=tot+1;
 37             update(l[pr],lx,mid,v,k);
 38     }
 39     else {
 40             r[tot]=tot+1;
 41             update(r[pr],mid+1,rx,v,k);
 42     }
 43 }
 44 void build(int rt,int lx,int rx){//初始化空树
 45     sum[rt]=0;
 46     if(lx==rx) return;
 47     l[rt]=++tot;
 48     int mid=(lx+rx)>>1;
 49     build(tot,lx,mid);
 50     r[rt]=++tot;
 51     build(tot,mid+1,rx);
 52 }
 53 int lowbit(int x){return x&(-x);}
 54 int Sum(int x){
 55     int res=0;
 56     for(int i=x;i;i-=lowbit(i)) res+=sum[l[use[i]]];
 57     return res;
 58 }
 59 void add(int x,int v,int k)
 60  {
 61      int tt;
 62     for(int i=x;i<=n;i+=lowbit(i)){
 63         tt=S[i];
 64         S[i]=tot+1;
 65         update(tt,1,nn,v,k);
 66     }
 67  }
 68 
 69 int query(int L,int R,int k){
 70     for(int i=L-1;i;i-=lowbit(i)) use[i]=S[i];//use记录要操作的线段树下标
 71     for(int i=R;i;i-=lowbit(i)) use[i]=S[i];
 72     int lx=1,rx=nn;
 73     int lt=T[L-1],rt=T[R];
 74     while(lx<rx){
 75         int mid=(lx+rx)>>1;
 76         int tmp=Sum(R)-Sum(L-1)+sum[l[rt]]-sum[l[lt]];
 77         if(k<=tmp){
 78             rx=mid;
 79             for(int i=L-1;i;i-=lowbit(i)) use[i]=l[use[i]];
 80             for(int i=R;i;i-=lowbit(i)) use[i]=l[use[i]];
 81             lt=l[lt];rt=l[rt];
 82         }
 83         else{
 84             lx=mid+1;k-=tmp;
 85             for(int i=L-1;i;i-=lowbit(i)) use[i]=r[use[i]];
 86             for(int i=R;i;i-=lowbit(i)) use[i]=r[use[i]];
 87             lt=r[lt];rt=r[rt];
 88         }
 89     }
 90     return f[lx];
 91 }
 92 char op[5];
 93 int q[10005][4],t;
 94 int main()
 95 {
 96     rd(t);
 97     while(t--){
 98           rd2(n,m);
 99           for(int i=1;i<=n;i++) {
100                   rd(a[i]);f[i]=a[i];
101           }
102           nn=n;
103           for(int i=1;i<=m;i++){
104               scanf("%s",op);
105               if(op[0]=='Q') {
106                   scanf("%d%d%d",&q[i][1],&q[i][2],&q[i][3]);
107                   q[i][0]=1;
108               }
109               else{
110                   scanf("%d%d",&q[i][1],&q[i][2]);
111                   q[i][0]=0;
112                   f[++nn]=q[i][2];
113               }
114           }
115           sort(f+1,f+1+nn);
116           nn=unique(f+1,f+1+nn)-f-1;//离散化线段树,并去重
117           tot=0;
118           T[0]=0;
119           build(0,1,nn);
120           for(int i=1;i<=n;i++){
121               T[i]=tot+1;          //T[i]记录第i个线段树的根
122               update(T[i-1],1,nn,h(a[i]),1);
123           }
124           for(int i=1;i<=n;i++) S[i]=T[0];
125          // int L,R,k,x;
126           for(int i=1;i<=m;i++){
127               if(q[i][0]){
128                   printf("%d\n",query(q[i][1],q[i][2],q[i][3]));
129               }
130               else{
131                   add(q[i][1],h(a[q[i][1]]),-1);
132                   add(q[i][1],h(q[i][2]),1);
133                   a[q[i][1]]=q[i][2];
134               }
135           }
136     }
137     return 0;
138 }
View Code

猜你喜欢

转载自www.cnblogs.com/wawawa8/p/9333339.html
今日推荐