• [填坑]主席树


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

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

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

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

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

    Poj2104

        静态查询区间第K大

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

        具体看代码:

        

      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
    ", 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前面有多少个即可。

      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
    ", 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:
    ", 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):

      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
    ", 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
    ", 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(线段树版本,好像时间还少点):

      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
    ", 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
    ", 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:

      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
    ", 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

         

  • 相关阅读:
    PAT 甲级 1120 Friend Numbers (20 分)
    AcWing 894. 拆分-Nim游戏
    AcWing 891. Nim游戏
    AcWing 892. 台阶-Nim游戏
    AcWing 893. 集合-Nim游戏
    洛谷P1433 吃奶酪
    洛谷P1118 [USACO06FEB]数字三角形`Backward Digit Su`…
    AcWing 125. 耍杂技的牛
    AcWing 104. 货仓选址 绝对值不等式
    AcWing 913. 排队打水 排序不等式贪心
  • 原文地址:https://www.cnblogs.com/yzcstc/p/3835500.html
Copyright © 2020-2023  润新知