主席树
https://blog.csdn.net/qq_39653331/article/details/78816987
https://www.cnblogs.com/zyf0163/p/4749042.html
感觉都写的好好,但是还是没有完全弄懂,目前只是懂了一点点QAQ,还是太菜了
然后贴上最近刷的几道题的代码吧
hdu 4417 Super Mario
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define N 100005 8 9 int root[N];//root[i]表示第i课线段树 10 int size[N*25],lchild[N*25],rchild[N*25]; 11 int tot; 12 13 void insert(int last,int cur,int L,int R,int k) //单点更新 14 { 15 size[cur]=size[last]+1;//将前一个树的信息复制过来 16 lchild[cur]=lchild[last]; 17 rchild[cur]=rchild[last]; 18 if(L==R)return ; 19 int mid=L+R>>1; 20 if(k<=mid) insert(lchild[last],lchild[cur]=++tot,L,mid,k);//对于需要更改的节点都需要新增节点 21 else insert(rchild[last],rchild[cur]=++tot,mid+1,R,k); 22 } 23 int query(int last,int cur,int l,int r,int L,int R) 24 { 25 if(l>r)return 0; 26 if(L==l&&r==R){ 27 return size[cur]-size[last]; 28 } 29 int mid=(L+R)>>1; 30 if(l>mid)return query(rchild[last],rchild[cur],l,r,mid+1,R); 31 else if(r<=mid)return query(lchild[last],lchild[cur],l,r,L,mid); 32 else return query(rchild[last],rchild[cur],mid+1,r,mid+1,R)+query(lchild[last],lchild[cur],l,mid,L,mid); 33 } 34 int a[100005]; 35 int b[100005]; 36 int main(){ 37 int t; 38 scanf("%d",&t); 39 int c=1; 40 while(t--){ 41 int n,m; 42 scanf("%d%d",&n,&m); 43 for(int i=1;i<=n;i++){ 44 scanf("%d",&a[i]); 45 b[i]=a[i]; 46 } 47 sort(b+1,b+n+1);//排序 48 int nn=unique(b+1,b+n+1)-b-1;//去重 49 //上面是在离散化处理 50 tot=0; 51 for(int i=1;i<=n;i++){ 52 int k=lower_bound(b+1,b+nn+1,a[i])-b;//找到a[i]在整个数列中是第几大 53 insert(root[i-1],root[i]=++tot,1,nn,k); 54 } 55 printf("Case %d:\n",c++); 56 for(int i=1;i<=m;i++){ 57 int l,r,h; 58 scanf("%d%d%d",&l,&r,&h); 59 l++;r++; 60 int k=upper_bound(b+1,b+1+nn,h)-b-1;//找到h在整个数列中是第几大 61 printf("%d\n",query(root[l-1],root[r],1,k,1,nn)); 62 } 63 } 64 return 0; 65 }
P3567 [POI2014]KUR-Couriers
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 const int N=5e5+6; 7 int n,m,cnt,root[N],a[N],x,y,k; 8 struct node 9 { 10 int l,r,sum; 11 }T[N*40]; 12 vector<int>v; 13 int getid(int x) 14 { 15 return lower_bound(v.begin(),v.end(),x)-v.begin()+1; 16 } 17 void update(int l,int r,int &x,int y,int pos) 18 { 19 T[++cnt]=T[y]; 20 T[cnt].sum++; 21 x=cnt; 22 if(l==r) 23 return ; 24 int mid=(l+r)>>1; 25 if(mid>=pos) 26 update(l,mid,T[x].l,T[y].l,pos); 27 else 28 update(mid+1,r,T[x].r,T[y].r,pos); 29 } 30 int query(int l,int r,int x,int y,int k) 31 { 32 if(l==r) 33 return l; 34 int mid=(l+r)>>1; 35 int sum1=T[T[y].l].sum-T[T[x].l].sum; 36 int sum2=T[T[y].r].sum-T[T[x].r].sum; 37 if(sum1+sum1>k) 38 return query(l,mid,T[x].l,T[y].l,k); 39 if(sum2+sum2>k) 40 return query(mid+1,r,T[x].r,T[y].r,k); 41 return 0; 42 } 43 int main() 44 { 45 scanf("%d%d",&n,&m); 46 for(int i=1;i<=n;i++) 47 { 48 scanf("%d",&a[i]); 49 update(1,n,root[i],root[i-1],a[i]); 50 } 51 for(int i=1;i<=m;i++) 52 { 53 scanf("%d%d",&x,&y); 54 printf("%d\n",query(1,n,root[x-1],root[y],y-x+1)); 55 } 56 return 0; 57 }
POJ 2104 K-th Number 主席树
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 const int N=1e5+6; 7 int n,m,cnt,root[N],a[N],x,y,k; 8 struct node 9 { 10 int l,r,sum; 11 }T[N*40]; 12 vector<int>v; 13 int getid(int x) 14 { 15 return lower_bound(v.begin(),v.end(),x)-v.begin()+1; 16 } 17 void update(int l,int r,int &x,int y,int pos) 18 { 19 T[++cnt]=T[y]; 20 T[cnt].sum++; 21 x=cnt; 22 if(l==r) 23 return ; 24 int mid=(l+r)>>1; 25 if(mid>=pos) 26 update(l,mid,T[x].l,T[y].l,pos); 27 else 28 update(mid+1,r,T[x].r,T[y].r,pos); 29 } 30 int query(int l,int r,int x,int y,int k) 31 { 32 if(l==r) 33 return l; 34 int mid=(l+r)>>1; 35 int sum=T[T[y].l].sum-T[T[x].l].sum; 36 if(sum>=k) 37 return query(l,mid,T[x].l,T[y].l,k); 38 else 39 return query(mid+1,r,T[x].r,T[y].r,k-sum); 40 } 41 int main() 42 { 43 scanf("%d%d",&n,&m); 44 for(int i=1;i<=n;i++) 45 { 46 scanf("%d",&a[i]); 47 v.push_back(a[i]); 48 } 49 sort(v.begin(),v.end()); 50 v.erase(unique(v.begin(),v.end()),v.end()); 51 for(int i=1;i<=n;i++) 52 { 53 update(1,n,root[i],root[i-1],getid(a[i])); 54 } 55 for(int i=1;i<=m;i++) 56 { 57 scanf("%d%d%d",&x,&y,&k); 58 printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]); 59 } 60 return 0;
主席树模板
1 #include <bits/stdc++.h> 2 using namespace std ; 3 bool Read ( int &x ) ///输入挂 4 { 5 char c = getchar() ; x = 0 ; bool f = 0 ; 6 while ( !isdigit(c) ) 7 { 8 if ( c == '-' ) f = 1 ; 9 if ( c == EOF ) return false ; c = getchar() ; 10 } 11 while ( isdigit(c) ) 12 { x = 10 * x + c - '0' ; c = getchar() ; } 13 if (f) x = -x ;return true ; 14 } 15 void Print ( int x ) ///输出挂 16 { 17 int len=0,a[50] ; 18 if ( x == 0 ) { putchar('0') ; return ; } 19 if ( x < 0 ) { putchar('-') ; x = -x ; } 20 while (x) { a[++len] = x%10 ; x /= 10 ; } 21 while (len) putchar(a[len--]+'0') ; 22 } 23 24 const int maxn=200010 ; 25 int n,m,rt[maxn],Rank[maxn],cnt ; 26 struct node 27 { 28 int l, r, v ; 29 } tree[maxn<<5] ; 30 struct nodd 31 { 32 int v, id ; 33 friend bool operator < ( nodd a, nodd b ) 34 { 35 return a.v == b.v ? a.id < b.id : a.v < b.v ; 36 } 37 } a[maxn] ; 38 ///这个k是数据key,不是第k大,x前面有一个取地址 39 void insert ( int K, int& x, int l, int r ) 40 {///这个是调用过程:insert(Rank[i],rt[i],1,n) ; 41 tree[++cnt]=tree[x] ; 42 x=cnt;///把rt[i]指向了rt[++cnt]这个真的根节点 43 tree[x].v++;///增加数量 44 int mid =(l+r)>>1 ; 45 if(l==r)return ; 46 if(K<=mid) insert(K,x[tree].l,l,mid) ; 47 else insert(K,x[tree].r,mid+1,r) ;///节点的编号机制不是*2和*2+1 48 ///而是根据调用次数由cnt管控,所以要存在每一个节点里 49 } 50 51 int query ( int rt1, int rt2, int l, int r, int K ) 52 { 53 if ( l == r ) return l ; 54 int mid = l+r >> 1 ; 55 int num = tree[rt2].l[tree].v - tree[rt1].l[tree].v ; 56 /**可加减性,为啥这样做,因为几点存的是前缀和, 57 我们要特定区间就把前面的减去咯。 58 你也可以这样认为:假设查第999大,当前节点总共管3个数, 59 你就需要把前面没用的减去咯。*/ 60 if ( K <= num ) 61 return query ( rt1[tree].l, rt2[tree].l, l, mid, K ) ; 62 else 63 return query ( rt1[tree].r, rt2[tree].r, mid+1, r, K-num ) ; 64 } 65 66 int main() 67 { 68 int i,j,k,x,y; 69 Read(n) ; Read(m) ; 70 for (i=1;i<=n;i++) ///离散 71 { 72 Read(a[i].v) ; 73 a[i].id=i ; 74 } 75 sort (a+1,a+n+1) ; 76 for (i=1;i<=n;i++) 77 Rank[a[i].id]=i ; 78 79 for (i=1;i<=n;i++) 80 { 81 rt[i]=rt[i-1] ; 82 /** 83 一开始有棵空树,不这样写,直接传root[1], 84 当需要递归到不需要改的区间,无法找到初试树的位置, 85 所以暂且把初试树的root完全复制过来 86 这样,因为每一棵树的根节点存储了它儿子的标号, 87 所以这一步相当于第1棵树完全等价与第0棵树, 88 只多开了一个root,其他的已经!!完全检索!!到上一棵树里 89 然后在新的树里把不一样的树枝修改成新的值, 90 并且新开空间就行了 91 所以之后递归就是if,else if,只选择一条路, 92 以此类推,第i棵树继承第i-1棵树就行了 93 */ 94 insert(Rank[i],rt[i],1,n); 95 } 96 97 while(m--) 98 { 99 Read(x);Read(y);Read(k) ; 100 Print(a[query(rt[x-1],rt[y],1,n,k)].v ) ; 101 putchar('\n') ; 102 } 103 104 return 0 ; 105 }