码迷,mamicode.com
首页 > 其他好文 > 详细

[填坑]主席树

时间:2014-07-16 22:49:03      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   strong   os   

     首先,可持久化数据结构,CLJ的论文里有讲。

     通俗点来讲,就是该数据结构保留历史版本信息,对应的有可持久化链表,可持久化线段树,可持久化树状数组。比如对于线段树更新操作,每次更新新建一棵线段树,那么就有任意一次时间点信息。

     当然,这样就非常耗空间,所以,对于线段树,每次只需要对于有更新的节点新建节点,否者可以用前一个版本的顶点(就是连接一下左右孩子就行了),这样,如果每次都是单点更改的话每次也就更改logn个点,空间复杂度nlogn。

     接下来我们讲讲什么是主席树(orz 主席)。

     如果我的理解没错的话(有错轻拍),主席树是一种特殊的线段树,特殊在于它具有前缀性质。也就是说,他对于每个i建立一颗线段树,维护1..i里面数字出现的信息,这样的话他又满足减法性,适合一些特殊问题(比如求区间第K大等经典问题)。

 

Poj2104

    静态查询区间第K大

    直接把出现的数字离散化,离散完建立线段树,接下去,对于每个1..i建立一个线段树,查询了(l, r),那么就是T[r]-T[l-1]的结果(T[i]表示第I棵线段树)

    具体看代码:

    

bubuko.com,布布扣
  1 /*
  2  * Author:  Yzcstc
  3  * Created Time:  2014/7/8 13:24:35
  4  * File Name: poj2104.cpp
  5  */
  6 #include<cstdio>
  7 #include<iostream>
  8 #include<cstring>
  9 #include<cstdlib>
 10 #include<cmath>
 11 #include<algorithm>
 12 #include<string>
 13 #include<map>
 14 #include<set>
 15 #include<vector>
 16 #include<queue>
 17 #include<stack>
 18 #include<ctime>
 19 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
 20 #define red(i, a, b) for (int i = (a); i >= (b); --i)
 21 #define M0(x)  memset(x, 0, sizeof(x))
 22 #define MP make_pair
 23 #define PB push_back
 24 #define eps 1e-8
 25 #define pi acos(-1.0)
 26 #define N 101000
 27 #define M (35 * N)
 28 typedef long long LL;
 29 using namespace std;
 30 int lson[M], rson[M], c[M];
 31 int a[N], n, m, q, tot, T[N];
 32 vector<int> v; 
 33 
 34 void init(){
 35     tot = 0;
 36     v.clear();
 37     for (int i = 1; i <= n; ++i)
 38         scanf("%d", &a[i]), v.push_back(a[i]);
 39     sort(v.begin(), v.end());
 40     v.erase(unique(v.begin(), v.end()), v.end());
 41     m = v.size();
 42 }
 43 
 44 int hash(const int x){
 45     return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
 46 }
 47 
 48 int build(int l, int r){
 49     int root = tot++;
 50     c[root] = 0;
 51     if (l < r){
 52         int mid = (l + r) >> 1;
 53         build(l , mid);
 54         build(mid + 1, r);
 55     }
 56     return root;
 57 }
 58 
 59 int updata(int root, int p, int val){ // 
 60     int newroot = tot++, tmp = newroot;
 61     int l = 1, r = m;
 62     while (1){
 63          c[newroot] = c[root] + val;
 64          if (l == r) break;
 65          int mid = (l + r) >> 1;
 66          if (p <= mid){
 67              lson[newroot] = tot++; rson[newroot] = rson[root]; //位于左子树,左子树更新节点,右子树用原来节点 
 68              newroot = lson[newroot]; root = lson[root];
 69              r = mid;
 70          }
 71          else 
 72          {
 73             lson[newroot] = lson[root]; rson[newroot] = tot++; //位于右子树 
 74             newroot = rson[newroot]; root = rson[root];
 75             l = mid + 1;
 76          }
 77     }
 78     return tmp;
 79 }
 80 
 81 int query(int lroot, int rroot, int k){  
 82     int ret = 0, l = 1, r = m;
 83     while (1){
 84         if (l == r) return v[l - 1];
 85         int mid = (l + r) >> 1;
 86         if (c[lson[rroot]] - c[lson[lroot]] >= k){ //左子树已经至少包含K个 
 87              rroot = lson[rroot];
 88              lroot = lson[lroot];
 89              r = mid;
 90         }
 91         else 
 92         {
 93             k -= (c[lson[rroot]] - c[lson[lroot]]); //答案维护右子树 
 94             rroot = rson[rroot];
 95             lroot = rson[lroot];
 96             l = mid + 1;
 97         }
 98     }
 99     return l;
100 }
101 
102 void solve(){
103     T[0] = build(1, m);
104     for (int i = 1; i <= n; ++i){
105         int p = hash(a[i]);
106         T[i] = updata(T[i-1], p, 1);
107     }
108     int l, r, k;
109     for (int i = 0; i < q; ++i){
110          scanf("%d%d%d", &l, &r, &k);
111          printf("%d\n", query(T[l-1], T[r], k));
112     }
113     
114 }
115 
116 int main(){
117     freopen("a.in", "r", stdin);
118     freopen("a.out", "w", stdout);
119     while (scanf("%d%d", &n, &q) != EOF){
120         init();
121         solve();
122     }
123     fclose(stdin);  fclose(stdout);
124     return 0;
125 }
View Code

hdu4417

    更上面差不多的题目,只不过查询改成了给定l,r,h,查询l,r间多少个不大于h。

    找到原数组中第一个<=h的数的下标P,直接查询P前面有多少个即可。

bubuko.com,布布扣
  1 /*
  2  * Author:  Yzcstc
  3  * Created Time:  2014/7/8 15:45:55
  4  * File Name: hdu4417.cpp
  5  */
  6 #include<cstdio>
  7 #include<iostream>
  8 #include<cstring>
  9 #include<cstdlib>
 10 #include<cmath>
 11 #include<algorithm>
 12 #include<string>
 13 #include<map>
 14 #include<set>
 15 #include<vector>
 16 #include<queue>
 17 #include<stack>
 18 #include<ctime>
 19 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
 20 #define red(i, a, b) for (int i = (a); i >= (b); --i)
 21 #define M0(x)  memset(x, 0, sizeof(x))
 22 #define MP make_pair
 23 #define PB push_back
 24 #define eps 1e-8
 25 #define pi acos(-1.0)
 26 #define N 101000
 27 #define M (N * 35)
 28 typedef long long LL;
 29 using namespace std;
 30 int a[N], t[N], n, m, q, cas;
 31 int c[M], lson[M], rson[M], tot, T[N];
 32 
 33 int build(const int l,const int r){
 34      int root = tot++;
 35      c[root] = 0;
 36      if (l < r){
 37         int mid = (l + r) >> 1;
 38         build(l, mid);
 39         build(mid + 1, r);      
 40      }
 41      return root;
 42 }
 43 
 44 void init(){
 45     tot = 0;
 46     scanf("%d%d", &n, &q);
 47     for (int i = 1; i <= n; ++i)
 48         scanf("%d", &a[i]), t[i] = a[i];
 49     sort(t + 1, t + 1 + n);
 50     m = unique(t + 1, t + 1 + n) - t - 1;
 51 }
 52 
 53 int hash(const int x){
 54     return lower_bound(t + 1, t + m + 1, x) - t;
 55 }
 56 
 57 int updata(int root,const int p,const int val){
 58     int newroot = tot++, tmp = newroot;
 59     int l = 1, r = m;
 60     while (1){
 61         c[newroot] = c[root] + val;
 62         if (l == r) break;
 63         int mid = (l + r) >> 1;
 64         if (p <= mid){
 65             lson[newroot] = tot++; rson[newroot] = rson[root];
 66             newroot = lson[newroot]; root = lson[root];
 67             r = mid;
 68         }
 69         else
 70         {
 71             lson[newroot] = lson[root]; rson[newroot] = tot++;
 72             newroot = rson[newroot]; root = rson[root];
 73             l = mid + 1;
 74         }
 75     }
 76     return tmp;
 77 }
 78 
 79 int query(int lroot, int rroot,const int p){
 80     if (!p) return 0;
 81     int ret = 0, l = 1, r = m;
 82     while (1){
 83           if (l == r) break;
 84           int mid = (l + r) >> 1;
 85           if (p <= mid){
 86                 lroot = lson[lroot];
 87                 rroot = lson[rroot];
 88                 r = mid;   
 89           }    
 90           else 
 91           {
 92                 ret += (c[lson[rroot]] - c[lson[lroot]]);
 93                 lroot = rson[lroot];
 94                 rroot = rson[rroot];
 95                 l = mid + 1;        
 96           }
 97     }
 98     return ret + c[rroot] - c[lroot];
 99 }
100 
101 void solve(){
102     T[0] = build(1, m);
103     for (int i = 1; i <= n; ++i){
104          int p = hash(a[i]);
105          T[i] = updata(T[i-1], p, 1); 
106     }
107     for (int i = 0; i < q; ++i){
108         int l, r, h;
109         scanf("%d%d%d", &l, &r, &h);
110         l++, r++;
111         int p = hash(h);
112         while (p > 0 && t[p] > h) --p;
113         printf("%d\n", query(T[l-1], T[r], p));    
114     }
115 }
116 
117 int main(){
118  //   freopen("a.in", "r", stdin);
119   //  freopen("a.out", "w", stdout);
120     scanf("%d", &cas);
121     for (int i = 1; i <= cas; ++i){
122         printf("Case %d:\n", i);
123         init();
124         solve();
125     }
126     fclose(stdin);  fclose(stdout);
127     return 0;
128 }
View Code

 

hdu4348

    更定n个数,然后4个操作:

         1. C l r d: [l, r]区间都增加d,并且时间点+1
         2. Q l r:查询当前[l,r]的和

         3. H l r t: 查询t时间点时[l,r]的和
         4. B t:数组返回到t时间的状态

    可以用离线算法或者在线算法。、,主要说说在线算法吧。。

     1)可以用采用可持久化树状数组,具体的话采用这位大牛博客的方法(区间修改,区间和的查询),然后对于每个时间点维护弄一个树状数组,

          遇到Back操作就把T以上的时间点出栈。。

     2)采用可持久化线段树,但是区间更改直接更改到某一小段(对于[l,r],由顶至下的所有第一个满足[L,r] <=[l,r]才需要更改),往下就不用更改,查询时把父节点增加值加上就行

    code(Bit):

bubuko.com,布布扣
  1 /*
  2  * Author:  Yzcstc
  3  * Created Time:  2014/7/9 12:59:07
  4  * File Name: hdu4348_bit.cpp
  5  */
  6 #include<cstdio>
  7 #include<iostream>
  8 #include<cstring>
  9 #include<cstdlib>
 10 #include<cmath>
 11 #include<algorithm>
 12 #include<string>
 13 #include<map>
 14 #include<set>
 15 #include<vector>
 16 #include<queue>
 17 #include<stack>
 18 #include<ctime>
 19 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
 20 #define red(i, a, b) for (int i = (a); i >= (b); --i)
 21 #define M0(x)  memset(x, 0, sizeof(x))
 22 #define MP make_pair
 23 #define PB push_back
 24 #define eps 1e-8
 25 #define pi acos(-1.0)
 26 #define N 101000
 27 typedef long long LL;
 28 using namespace std;
 29 struct oo{
 30     LL d, dt;
 31     int T;
 32     oo(LL _d = 0, LL _dt = 0, int _T = 0):d(_d),dt(_dt), T(_T){}
 33     void updata(long long d1, long long dt1, int T1){
 34         d += d1;
 35         dt += dt1;
 36         T = T1;
 37     }
 38 };
 39 vector<oo> b[N]; //b[x]记录b[x][i]记录第b[i].T个时间点的记录 
 40 long long a[N], sum[N];
 41 int n, m;
 42 
 43 int lowbit(const int x){
 44     return x & (-x);
 45 }
 46 
 47 void updata(int x,const long long v,const int T){
 48     long long vt = v * x;
 49     for (; x <= n; x += lowbit(x)){
 50         int sz = b[x].size();
 51         b[x].PB(b[x][sz-1]); //需要更改的点新建,否则信息都跟b[x][sz-1]一样(T不一样,但是不影响) 
 52         sz++;
 53         b[x][sz-1].updata(v, vt, T);
 54     }
 55 }
 56 
 57 long long query(int x,const int T){
 58     long long sd = 0, sdt = 0;
 59     int cur_x = x;
 60     for (; x; x -= lowbit(x)){
 61         int sz = b[x].size();
 62         while (sz && b[x][sz-1].T > T) --sz; //你会疑惑可能b[x][sz-1]最后的时间点不是T(因为前面新增时没更改到) 
 63         sd += b[x][sz-1].d; //那么就对了,没更改到前一个节点信息跟现在的一模一样,直接用不就得了何必更改。。 
 64         sdt += b[x][sz-1].dt;
 65     }
 66     return (cur_x + 1) * sd - sdt; //
 67 }
 68 
 69 long long query(const int l,const int r,const int T){
 70     return sum[r] - sum[l-1] + query(r, T) - query(l-1, T);
 71 }
 72 
 73 void goback(int T){
 74     for (int i = 1; i <= n; ++i){
 75         int sz = b[i].size();
 76         while (sz && b[i][sz-1].T > T) b[i].pop_back(), sz--;
 77     }
 78 }
 79 
 80 void init(){
 81     for (int i = 1; i <= n; ++i){
 82         b[i].clear();
 83         b[i].PB(oo(0LL, 0LL, 0));
 84     }
 85     for (int i = 1; i <= n; ++i)
 86         scanf("%I64d", &a[i]), sum[i] = sum[i-1] + a[i];
 87 }
 88 
 89 void solve(){
 90     char S[12];
 91     int l, r, d;
 92     int now = 0;
 93     for (int i = 0; i < m; ++i){
 94         scanf("%s", S);
 95         if (S[0] == Q){
 96             scanf("%d%d", &l, &r);
 97             printf("%I64d\n", query(l, r, now));
 98         }
 99         if (S[0] == C){
100             scanf("%d%d%d", &l, &r, &d);
101             ++now;
102             updata(l, d, now);
103             updata(r+1, -d, now);
104         }
105         if (S[0] == H){
106             scanf("%d%d%d", &l, &r, &d);
107             printf("%I64d\n", query(l, r, d));
108         }
109         if (S[0] == B){
110             scanf("%d", &l);
111             now = l;
112             goback(l);
113         }
114     }
115 }
116 
117 int main(){
118     freopen("a.in", "r", stdin);
119     freopen("a.out", "w", stdout);
120     int cas = 0;
121     while (scanf("%d%d", &n, &m) != EOF){
122         if (cas++) puts("");
123         init();
124         solve();
125     }
126     fclose(stdin);  fclose(stdout);
127     return 0;
128 }
View Code

   code(线段树版本,好像时间还少点):

bubuko.com,布布扣
  1 /*
  2  * Author:  Yzcstc
  3  * Created Time:  2014/7/9 12:59:07
  4  * File Name: hdu4348_bit.cpp
  5  */
  6 #include<cstdio>
  7 #include<iostream>
  8 #include<cstring>
  9 #include<cstdlib>
 10 #include<cmath>
 11 #include<algorithm>
 12 #include<string>
 13 #include<map>
 14 #include<set>
 15 #include<vector>
 16 #include<queue>
 17 #include<stack>
 18 #include<ctime>
 19 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
 20 #define red(i, a, b) for (int i = (a); i >= (b); --i)
 21 #define M0(x)  memset(x, 0, sizeof(x))
 22 #define MP make_pair
 23 #define PB push_back
 24 #define eps 1e-8
 25 #define pi acos(-1.0)
 26 #define N 110010
 27 #define M 3450100
 28 typedef long long LL;
 29 using namespace std;
 30 int lson[M], rson[M], c[M], tot, a[N], T[N], now, n, m;
 31 long long sum[M];
 32 
 33 int build(int l, int r){
 34     int root = tot++;
 35     c[root] = 0;
 36     if (l == r) sum[root] = a[l];
 37     else 
 38     {
 39          int mid = (l + r) >> 1;
 40          lson[root] = build(l, mid);
 41          rson[root] = build(mid + 1, r);
 42          sum[root] = sum[lson[root]] + sum[rson[root]];
 43     }
 44     return root;
 45 }
 46 
 47 int updata(int rt, const int L, const int R, const int l,const int r, const int v){
 48     int root = tot++;
 49     c[root] = c[rt]; sum[root] = sum[rt];
 50     lson[root] =  lson[rt]; rson[root] = rson[rt];
 51     if (l <= L && R <= r){
 52            c[root] += v;
 53            sum[root] += (__int64)(R-L+1) * v;      
 54            return root;
 55     }
 56     int mid = (L + R) >> 1;
 57     if (l <= mid) 
 58           lson[root] = updata(lson[rt], L, mid, l, r, v);
 59     if (r > mid) 
 60           rson[root] = updata(rson[rt], mid+1, R, l, r, v); 
 61     sum[root] = sum[lson[root]] + sum[rson[root]] + c[root] * (R-L+1);  
 62     return root;
 63 }
 64 
 65 long long query(int rt,const int L, const int R, const int l, const int r, int v){
 66      if (l <= L && R <= r)
 67            return sum[rt] + v * (R-L+1);
 68      int mid = (L + R) >> 1;
 69      long long ret = 0;
 70      if (l <= mid) 
 71          ret += query(lson[rt], L, mid, l, r, v + c[rt]);
 72      if (r > mid)
 73          ret += query(rson[rt], mid+1, R, l, r, v + c[rt]);
 74      return ret;
 75 }
 76 
 77 void goback(int time){
 78      if (now == time) return;
 79      now = time;
 80      tot = T[time+1]; 
 81 }
 82 
 83 void init(){
 84     for (int i = 1; i <= n; ++i)
 85         scanf("%d", &a[i]);
 86     tot = 0;
 87     T[0] = build(1, n);
 88 }
 89 
 90 void solve(){
 91     char S[12];
 92     int l, r, d;
 93     now = 0;
 94     for (int i = 1; i <= m; ++i){
 95         scanf("%s", S);
 96         if (S[0] == Q){
 97             scanf("%d%d", &l, &r);
 98             printf("%I64d\n", query(T[now], 1, n, l, r, 0));
 99         }
100         if (S[0] == C){
101             scanf("%d%d%d", &l, &r, &d);
102             ++now;
103             T[now] = updata(T[now-1], 1, n, l, r, d);
104         }
105         if (S[0] == H){
106             scanf("%d%d%d", &l, &r, &d);
107             printf("%I64d\n", query(T[d], 1, n, l, r, 0));
108         }
109         if (S[0] == B){
110             scanf("%d", &l);
111             goback(l);
112         }
113     }
114 }
115 
116 int main(){
117 //    freopen("a.in", "r", stdin);
118 //    freopen("a.out", "w", stdout);
119     int cas = 0;
120     while (scanf("%d%d", &n, &m) != EOF){
121         if (cas++) puts("");
122         init();
123         solve();
124     }
125     fclose(stdin);  fclose(stdout);
126     return 0;
127 }
View Code

 

Zoj2112&&Bzoj1901

    动态区间第K大

    首先,如果是静态的话,那么可以直接用主席树维护。但是更改问题就来了。

    不过试想一下,如果知道某个节点前面的修改情况,那么问题不就解决了吗。这个不就可以用树状数组来维护吗。。

     举个栗子把:

     比如原数组是: 1 5 2 3 4 6

     当前修改信息是:1(位置1) -> 2, 3(位置4) ->4

     那么在查询[2,4]第2大时,比如对于4,我们查询在原数组区间中为第2大,前面更改信息是少了3,多了4,一加一减为0,答案就是4了。

     具体实现的话:就是对于N个线段树扔进树状数组里进行维护,也就是说树状数组的每个节点对应一棵线段树。

     代码太丑就不贴了。。

     当然也可以用线段树套平衡树的做法实现。。不过太麻烦不写了。。

     具体点这

 

Spoj10628&&Bzoj2588

    树上第K大:(spoj)给定u,v,k,求u到v路径上的第K大

                    (bzoj)给定u,v,k,求u ^ lastans到v路径上的第K大,lastans为上次询问答案

    对于spoj10628,可以离线求出lca,但是bzoj只能在线。我用的是欧拉序列+st求的。。

    其他的话,就判断root->u,root->v,root->lca之间做即可。传统的主席树是在线性上的。。这里改成树的即可

    具体看代码吧

   code:

bubuko.com,布布扣
  1 /*
  2  * Author:  Yzcstc
  3  * Created Time:  2014/7/10 16:04:29
  4  * File Name: spoj10628.cpp
  5  */
  6 #include<cstdio>
  7 #include<iostream>
  8 #include<cstring>
  9 #include<cstdlib>
 10 #include<cmath>
 11 #include<algorithm>
 12 #include<string>
 13 #include<map>
 14 #include<set>
 15 #include<vector>
 16 #include<queue>
 17 #include<stack>
 18 #include<ctime>
 19 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
 20 #define red(i, a, b) for (int i = (a); i >= (b); --i)
 21 #define M0(x)  memset(x, 0, sizeof(x))
 22 #define MP make_pair
 23 #define PB push_back
 24 #define eps 1e-8
 25 #define pi acos(-1.0)
 26 #define two(i) (1 << i)
 27 #define N 101000
 28 #define M 4100000
 29 typedef long long LL;
 30 using namespace std;
 31 int T[N << 1], t[N << 1], a[N << 1], n, m, q;
 32 int lson[M], rson[M], c[M], tot;
 33 int f[N<<1][20], dep[N<<1], fv[N<<1], lv[N<<1], fa[N<<1], d[N << 1], inx;
 34 vector<int> e[N << 1];
 35 
 36 void dfs(int u, int depth){
 37     dep[u] = depth;
 38     fv[u] = lv[u] = ++inx;
 39     d[inx] = u;
 40     for (int i = 0; i < e[u].size(); ++i){
 41         int v = e[u][i];
 42         if (dep[v]) continue;
 43         fa[v] = u;
 44         dfs(v, depth + 1);
 45         d[lv[u] = ++inx] = u;
 46     }
 47         
 48 }
 49 
 50 void initrmq(){ //求出st的dp数组 
 51     M0(fa);
 52     M0(dep);
 53     dfs(1, 1);
 54     M0(f);
 55     for (int i = 1; i <= inx; ++i)
 56         f[i][0] = d[i];
 57     for (int j = 1; two(j) <= inx; ++j)
 58         for (int i = 1; i + two(j) - 1 <= inx; ++i)
 59            f[i][j] = (dep[f[i][j-1]] < dep[f[i + two(j-1)][j-1]]) ? f[i][j-1] : f[i+two(j-1)][j-1];          
 60 }
 61 
 62 void init(){
 63     tot = inx = 0;
 64     M0(a);
 65     for (int i = 0; i <= n; ++i) e[i].clear();
 66     for (int i = 1; i <= n; ++i)
 67         scanf("%d", &a[i]), t[i-1] = a[i];
 68     for (int i = 1; i < n; ++i){
 69         int u, v;
 70         scanf("%d%d", &u, &v);
 71         e[u].PB(v);
 72         e[v].PB(u);
 73     }
 74     sort(t, t + n);
 75     m = unique(t, t + n) - t;
 76     initrmq();
 77 }
 78 
 79 int queryrmq(const int L,const int R){ //st查询最小值 
 80     int l = min(fv[L], fv[R]);
 81     int r = max(lv[L], lv[R]);
 82     int k = (int)(log(r-l+1.0) / log(2.0));
 83     return dep[f[l][k]] < dep[f[r-two(k)+1][k]] ? f[l][k] : f[r-two(k)+1][k];
 84 }
 85 
 86 int hash(const int x){
 87     return lower_bound(t, t + m, x) - t;
 88 }
 89 
 90 int build(const int l,const int r){
 91     int root = tot++;
 92     if (l < r){
 93         int mid = (l + r) >> 1;
 94         lson[root] = build(l, mid);
 95         rson[root] = build(mid+1, r);
 96     }
 97     return root;
 98 }
 99 
100 int updata(int rt, const int p, const int v){
101     int root = tot++, tmp = root;
102     int l = 0, r = m - 1;
103     while (1){
104         c[root] = c[rt] + v;
105         if (l == r) break;
106         int mid = (l + r) >> 1;
107         if (p <= mid){
108             lson[root] = tot++; rson[root] = rson[rt];
109             root = lson[root]; rt = lson[rt];
110             r = mid;
111         }
112         else
113         {
114             lson[root] = lson[rt]; rson[root] = tot++;
115             root = rson[root]; rt = rson[rt];
116             l = mid + 1;
117         }
118     }
119     return tmp;
120 }
121 
122 int query(int rtu, int rtv, int rtf, int fp, int k){
123     int l = 0, r = m - 1;
124     while (l < r){
125         int mid = (l + r) >> 1;
126         int tmp = c[lson[rtu]] + c[lson[rtv]] - 2 * c[lson[rtf]] + (fp <= mid && fp >= l); //多减了lca的答案,所以要加上去 
127         if (tmp >= k){
128             rtu = lson[rtu];
129             rtv = lson[rtv];
130             rtf = lson[rtf];
131             r = mid;
132         }
133         else
134         {
135             rtu = rson[rtu];
136             rtv = rson[rtv];
137             rtf = rson[rtf];
138             k -= tmp;
139             l = mid + 1;    
140         }
141     }
142     return l;
143 }
144 
145 void dfs(const int u){ //树结构上建主席树 
146     T[u] = updata(T[fa[u]], hash(a[u]), 1);
147     for (int i = 0; i < e[u].size(); ++i){
148         int v = e[u][i];
149         if (v == fa[u]) continue;
150         dfs(v);
151     }
152 }
153 
154 void solve(){
155     int u, v, k, fuv;
156     T[0] = build(0, m-1);
157     dfs(1);
158     for (int i = 0; i < q; ++i){
159         scanf("%d%d%d", &u, &v, &k);
160         fuv = queryrmq(u, v);
161         printf("%d\n", t[query(T[u], T[v], T[fuv],hash(a[fuv]), k)]);
162     }
163 }
164 
165 int main(){
166 //    freopen("a.in", "r", stdin);
167 //    freopen("a.out", "w", stdout);
168     while (scanf("%d%d", &n, &q) != EOF){
169         init();
170         solve();
171     }
172     fclose(stdin);  fclose(stdout);
173     return 0;
174 }
View Code

 

     

[填坑]主席树,布布扣,bubuko.com

[填坑]主席树

标签:style   blog   http   color   strong   os   

原文地址:http://www.cnblogs.com/yzcstc/p/3835500.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!