专题训练之主席树

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 }
HDOJ2665
 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 }
HDOJ2665(递归版)

 

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 }
HDOJ4417(在线)
  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

专题补全计划

UESTC 电子科大专题训练 数据结构 A

数据结构之主席树

BZOJ2874训练士兵(主席树)

BZOJ2874 训练士兵 主席树