专题训练之主席树
Posted jackyan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了专题训练之主席树相关的知识,希望对你有一定的参考价值。
推荐几个博客:http://www.cnblogs.com/zyf0163/p/4749042.html 树状结构之主席树
https://blog.csdn.net/creatorx/article/details/75446472 最详细的讲解,让你一次学会主席树
https://blog.csdn.net/jerans/article/details/75807666 主席树题集
https://blog.csdn.net/HTT_H/article/details/47704209 主席树入门专题
https://www.cnblogs.com/RabbitHu/p/segtree.html 递归版主席树
递归版模板大体结构:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=5e4+10; 7 const int maxm=2e6+10; 8 int tot; 9 int c[maxm],lson[maxm],rson[maxm]; 10 int T[maxn]; 11 12 void build(int &root,int l,int r) 13 { 14 root=++tot; 15 if ( l==r ) return; 16 int mid=(l+r)/2; 17 build(lson[root],l,mid); 18 build(rson[root],mid+1,r); 19 } 20 21 void update(int root,int &rt,int p,int val,int l,int r) 22 { 23 rt=++tot; 24 lson[rt]=lson[root],rson[rt]=rson[root]; 25 c[rt]=c[root]+val; 26 if ( l==r ) return; 27 int mid=(l+r)/2; 28 if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid); 29 else update(rson[rt],rson[rt],p,val,mid+1,r); 30 } 31 32 int query(int rt,int L,int R,int l,int r) 33 { 34 if ( L<=l && r<=R ) return c[rt]; 35 int mid=(l+r)/2; 36 int ans=0; 37 if ( L<=mid ) ans+=query(lson[rt],L,R,l,mid); 38 if ( R>mid ) ans+=query(rson[rt],L,R,mid+1,r); 39 return ans; 40 }
1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665
(POJ2104)http://poj.org/problem?id=2104
(POJ2761)http://poj.org/problem?id=2761
题意:求区间第K大,主席树模板题
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int maxn=1e5+10; 7 const int maxm=3e6+10; 8 int n,q,m,tot; 9 int a[maxn],t[maxn]; 10 int T[maxn],lson[maxm],rson[maxm],c[maxm]; 11 12 void init_hash() 13 { 14 for ( int i=1;i<=n;i++ ) t[i]=a[i]; 15 sort(t+1,t+1+n); 16 m=unique(t+1,t+1+n)-(t+1); 17 } 18 19 int build(int l,int r) 20 { 21 int root=tot++; 22 c[root]=0; 23 if ( l!=r ) 24 { 25 int mid=(l+r)/2; 26 lson[root]=build(l,mid); 27 rson[root]=build(mid+1,r); 28 } 29 return root; 30 } 31 32 int hash_(int x) 33 { 34 return lower_bound(t+1,t+1+m,x)-t; 35 } 36 37 int update(int root,int pos,int val) 38 { 39 int rt=tot++,tmp=rt; 40 c[rt]=c[root]+val; 41 int l=1,r=m; 42 while ( l<r ) 43 { 44 int mid=(l+r)/2; 45 if ( pos<=mid ) 46 { 47 lson[rt]=tot++;rson[rt]=rson[root]; 48 rt=lson[rt];root=lson[root]; 49 r=mid; 50 } 51 else 52 { 53 rson[rt]=tot++;lson[rt]=lson[root]; 54 rt=rson[rt];root=rson[root]; 55 l=mid+1; 56 } 57 c[rt]=c[root]+val; 58 } 59 return tmp; 60 } 61 62 int query(int lrt,int rrt,int k) 63 { 64 int l=1,r=m; 65 while ( l<r ) 66 { 67 int mid=(l+r)/2; 68 if ( c[lson[rrt]]-c[lson[lrt]]>=k ) 69 { 70 r=mid; 71 lrt=lson[lrt]; 72 rrt=lson[rrt]; 73 } 74 else 75 { 76 l=mid+1; 77 k-=c[lson[rrt]]-c[lson[lrt]]; 78 lrt=rson[lrt]; 79 rrt=rson[rrt]; 80 } 81 } 82 return l; 83 } 84 85 int main() 86 { 87 int Case; 88 scanf("%d",&Case); 89 while ( Case-- ) 90 { 91 scanf("%d%d",&n,&q); 92 tot=0; 93 for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]); 94 init_hash(); 95 T[0]=build(1,m); 96 for ( int i=1;i<=n;i++ ) 97 { 98 int pos=hash_(a[i]); 99 T[i]=update(T[i-1],pos,1); 100 } 101 while ( q-- ) 102 { 103 int l,r,k; 104 scanf("%d%d%d",&l,&r,&k); 105 printf("%d\\n",t[query(T[l-1],T[r],k)]); 106 } 107 } 108 return 0; 109 }
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=1e5+10; 7 const int maxm=3e6+10; 8 int tot,n,q,m; 9 int a[maxn],t[maxn]; 10 int c[maxm],lson[maxm],rson[maxm]; 11 int T[maxn]; 12 13 void init_hash() 14 { 15 for ( int i=1;i<=n;i++ ) t[i]=a[i]; 16 sort(t+1,t+1+n); 17 m=unique(t+1,t+1+n)-(t+1); 18 } 19 20 int hash_(int x) 21 { 22 return lower_bound(t+1,t+1+m,x)-t; 23 } 24 25 void build(int &root,int l,int r) 26 { 27 root=++tot; 28 if ( l==r ) return; 29 int mid=(l+r)/2; 30 build(lson[root],l,mid); 31 build(rson[root],mid+1,r); 32 } 33 34 void update(int root,int &rt,int p,int val,int l,int r) 35 { 36 rt=++tot; 37 lson[rt]=lson[root],rson[rt]=rson[root]; 38 c[rt]=c[root]+val; 39 if ( l==r ) return; 40 int mid=(l+r)/2; 41 if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid); 42 else update(rson[rt],rson[rt],p,val,mid+1,r); 43 } 44 45 int query(int rt_,int rt,int l,int r,int k) 46 { 47 if ( l==r ) return l; 48 int mid=(l+r)/2; 49 int sum=c[lson[rt_]]-c[lson[rt]]; 50 if ( sum>=k ) return query(lson[rt_],lson[rt],l,mid,k); 51 else return query(rson[rt_],rson[rt],mid+1,r,k-sum); 52 } 53 54 int main() 55 { 56 int Case; 57 scanf("%d",&Case); 58 while ( Case-- ) 59 { 60 scanf("%d%d",&n,&q); 61 tot=0; 62 for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]); 63 init_hash(); 64 build(T[0],1,m); 65 for ( int i=1;i<=n;i++ ) 66 { 67 int pos=hash_(a[i]); 68 update(T[i-1],T[i],pos,1,1,m); 69 } 70 while ( q-- ) 71 { 72 int l,r,k; 73 scanf("%d%d%d",&l,&r,&k); 74 printf("%d\\n",t[query(T[r],T[l-1],1,m,k)]); 75 } 76 } 77 return 0; 78 }
2.(HDOJ4417)http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:求给定区间<=k的数有多少
分析:在模板上将query部分修改一下即可,对于区间[L,R]来说,只需要将第R颗线段树上的[0,k]区间内的值减去第L-1颗线段树上对应区间即可。离线在线都行,离线做法需要将每次访问的k也添加进入hash数组,而对于在线来说转化后的数转化前相对于给定的k来说只能变小不能变大即可
注意:题目给的区间范围从0开始,要将其转化成从1开始
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int maxn=1e5+10; 7 const int maxm=3e6+10; 8 int n,q,m,tot; 9 int a[maxn],t[maxn]; 10 int T[maxn],lson[maxm],rson[maxm],c[maxm]; 11 12 void init_hash() 13 { 14 for ( int i=1;i<=n;i++ ) t[i]=a[i]; 15 sort(t+1,t+1+n); 16 m=unique(t+1,t+1+n)-(t+1); 17 } 18 19 int build(int l,int r) 20 { 21 int root=tot++; 22 c[root]=0; 23 if ( l!=r ) 24 { 25 int mid=(l+r)/2; 26 lson[root]=build(l,mid); 27 rson[root]=build(mid+1,r); 28 } 29 return root; 30 } 31 32 int hash_(int x) 33 { 34 return lower_bound(t+1,t+1+m,x)-t; 35 } 36 37 int update(int root,int pos,int val) 38 { 39 int rt=tot++,tmp=rt; 40 c[rt]=c[root]+val; 41 int l=1,r=m; 42 while ( l<r ) 43 { 44 int mid=(l+r)/2; 45 if ( pos<=mid ) 46 { 47 lson[rt]=tot++;rson[rt]=rson[root]; 48 rt=lson[rt];root=lson[root]; 49 r=mid; 50 } 51 else 52 { 53 rson[rt]=tot++;lson[rt]=lson[root]; 54 rt=rson[rt];root=rson[root]; 55 l=mid+1; 56 } 57 c[rt]=c[root]+val; 58 } 59 return tmp; 60 } 61 62 int query(int lrt,int rrt,int k) 63 { 64 int ret=0; 65 int l=1,r=m; 66 while ( l<r ) 67 { 68 int mid=(l+r)/2; 69 if ( k<=mid ) 70 { 71 r=mid; 72 lrt=lson[lrt]; 73 rrt=lson[rrt]; 74 } 75 else 76 { 77 ret+=c[lson[rrt]]-c[lson[lrt]]; 78 l=mid+1; 79 lrt=rson[lrt]; 80 rrt=rson[rrt]; 81 } 82 } 83 ret+=c[rrt]-c[lrt]; 84 return ret; 85 } 86 87 int main() 88 { 89 int Case,h; 90 scanf("%d",&Case); 91 for ( h=1;h<=Case;h++ ) 92 { 93 scanf("%d%d",&n,&q); 94 tot=0; 95 for ( int i=1;i<=n;i++ ) 96 { 97 scanf("%d",&a[i]); 98 a[i]++; 99 } 100 init_hash(); 101 T[0]=build(1,m); 102 for ( int i=1;i<=n;i++ ) 103 { 104 int pos=hash_(a[i]); 105 T[i]=update(T[i-1],pos,1); 106 } 107 printf("Case %d:\\n",h); 108 while ( q-- ) 109 { 110 int l,r,k,p; 111 scanf("%d%d%d",&l,&r,&k); 112 l++,r++,k++; 113 p=hash_(k); 114 if ( t[p]>k ) p--; 115 if ( p==0 ) printf("0\\n"); 116 else printf("%d\\n",query(T[l-1],T[r],p)); 117 } 118 } 119 return 0; 120 }
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int maxn=1e5+10; 7 const int maxm=3e6+10; 8 int n,q,m,tot; 9 int a[maxn],t[maxn*2],l[maxn],r[maxn],val[maxn]; 10 int T[maxn],lson[maxm],rson[maxm],c[maxm]; 11 12 void init_hash() 13 { 14 for ( int i=1;i<=n;i++ ) t[i]=a[i]; 15 for ( int i=1;i<=q;i++ ) t[i+n]=val[i]; 16 sort(t+1,t+1+n+q); 17 m=unique(t+1,t+1+n+q)-(t+1); 18 } 19 20 int build(int l,int r) 21 { 22 int root=tot++; 23 c[root]=0; 24 if ( l!=r ) 25 { 26 int mid=(l+r)/2; 27 lson[root]=build(l,mid); 28 rson[root]=build(mid+1,r); 29 } 30 return root; 31 } 32 专题训练之Trie