主席树专题

首先说一下我对主席树的理解:

其实主席树就是一棵可持久化权值线段树。权值线段树就是意思是将值作为线段树的L,R下标,而Sum属性代表的是当前M下标的值有多少个。

可持久化,其实就是保存历史版本的意思。相当于每做一次更新操作,把原来的版本复制一份,再修改一些节点。

但是问题来了直接复制肯定大量空间浪费,就相当于开了若干棵线段树,直接爆炸。所以我们要尽可能使用之前的信息。只要之前的节点不变的,就将当前版本的节点直接连到之前节点,不用新开节点。

这样的话每次修改只涉及一个值的话,那么修改的路径最多是树高,是logn的。那么每次新开的节点不超过logn,大大节省了空间。

以上就是主席树的基本思想。

然后入门视频推荐一下UESTC的讲解视频,虽然说讲解的也不是特别特别清楚,但是那个代码我感觉还是挺不错的。再结合手推基本可以理解精髓所在。

入门题:

HDU2665  求区间第K大 

题解:模板题。建好主席树后,查询就是相当于利用前缀和每次计算操作在L-R之间的数的个数,对于满足第K大,二分查找即可。而主席树本身具有二分的性质,直接根据左儿子的sum值(即比当前M小于等于的值的个数)和k比较,就可以判断往哪边走了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<cmath>
 7 #include<string>
 8 #include<set>
 9 #include<queue>
10 #include<map>
11 using namespace std;
12 const int inf=(1<<30)-1;
13 const int maxn=100010;
14 #define REP(i,n) for(int i=(0);i<(n);i++)
15 #define FOR(i,j,n) for(int i=(j);i<=(n);i++)
16 #define Rep(x) for(int i=head[x],y;~i;i=e[i].next) if(!vis[y=e[i].to])
17 typedef long long ll;
18 typedef pair<int,int> PII;
19 int IN(){
20     int c,f,x;
21     while (!isdigit(c=getchar())&&c!='-');c=='-'?(f=1,x=0):(f=0,x=c-'0');
22     while (isdigit(c=getchar())) x=(x<<1)+(x<<3)+c-'0';return !f?x:-x;
23 }
24 #define de(x) cout << #x << "=" << x << endl
25 #define MP make_pair
26 #define PB push_back
27 #define fi first
28 #define se second
29 int n,m,T;
30 int a[maxn],rt[maxn],tot;
31 struct data{
32     int l,r,sum;
33 }t[maxn*20];
34 vector<int> v;
35 inline getid(int x) {
36     return lower_bound(v.begin(),v.end(),x)-v.begin()+1; 
37 }
38 void build(int l,int r,int &x) {
39     x=++tot;t[x].sum=0;
40     if(l==r) return;
41     int m=(l+r)>>1;
42     build(l,m,t[x].l);
43     build(m+1,r,t[x].r);
44 }
45 void update(int l,int r,int &x,int y,int k) {
46     x=++tot;t[x]=t[y];t[x].sum++;
47     if(l==r) return;
48     int m=(l+r)>>1;
49     if(k<=m) update(l,m,t[x].l,t[y].l,k);
50     else update(m+1,r,t[x].r,t[y].r,k);
51 }
52 int query(int l,int r,int x,int y,int k) {
53     if(l==r) return l;
54     int m=(l+r)>>1;
55     int sum=t[t[y].l].sum-t[t[x].l].sum;
56     if(k<=sum) return query(l,m,t[x].l,t[y].l,k);
57     else return query(m+1,r,t[x].r,t[y].r,k-sum);
58 }
59 int main()
60 {
61     int T;scanf("%d",&T);
62     while(T--) {
63         scanf("%d%d",&n,&m);
64         for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.PB(a[i]);
65         sort(v.begin(),v.end());
66         v.erase(unique(v.begin(),v.end()),v.end());
67         int cnt=v.size();
68         tot=0;
69         build(1,cnt,rt[0]);
70         for(int i=1;i<=n;i++) {
71             update(1,cnt,rt[i],rt[i-1],getid(a[i]));
72         } 
73         while(m--) {
74             int l,r,x;scanf("%d%d%d",&l,&r,&x);
75             printf("%d\n",v[query(1,cnt,rt[l-1],rt[r],x)-1]);
76         }
77     }
78     return 0;
79 }
View Code

猜你喜欢

转载自www.cnblogs.com/caozy623/p/9142901.html