森林 BZOJ 3123

题解:

第k大直接用主席树解决

合并利用启发式合并,将较小的连接到较大的树上

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<algorithm>
  7 using namespace std;
  8 const int inf = 2e9;
  9 const int logn = 17;
 10 const int maxn = 8e4 + 233;
 11 const int maxm = 2e5;
 12 int t, n, m, q;
 13 int sum[maxn * 500], lc[maxn * 500], rc[maxn * 500];
 14 int rt[maxn];
 15 int tot, nex[maxm], fir[maxm], ver[maxm];
 16 int num, cnt;
 17 int ans;
 18 int disp[maxn];
 19 int si[maxn], dep[maxn], anc[maxn][logn + 1];
 20 int fat[maxn];
 21 int val[maxn];
 22 bool vis[maxn];
 23 inline int Get()
 24 {
 25     int x;
 26     char c;
 27     bool o = false;
 28     while((c = getchar()) < '0' || c > '9')
 29         if(c == '-') o = true;
 30     x = c - '0';
 31     while((c = getchar()) >= '0' && c <= '9')
 32         x = x * 10 + c - '0';
 33     return (o) ? -x : x;
 34 }
 35 inline void Reset()
 36 {
 37     for(int i = 1; i <= n; ++i)
 38         disp[i] = val[i], fat[i] = i, si[i] = 1;
 39 }
 40 inline void Disperse()
 41 {
 42     sort(disp + 1, disp + 1 + n);
 43     disp[0] = -inf;
 44     for(int i = 1; i <= n; ++i)
 45         if(disp[i] != disp[i - 1])
 46             disp[++num] = disp[i];
 47     for(int i = 1; i <= n; ++i)
 48         val[i] = lower_bound(disp + 1, disp + 1 + num, val[i]) - disp;
 49 }
 50 inline void Ins(int x, int y)
 51 {
 52     nex[++tot] = fir[x], fir[x] = tot, ver[tot] = y;
 53 }
 54 inline int Find(int x)
 55 {
 56     return (fat[x] != x) ? fat[x] = Find(fat[x]) : x;
 57 }
 58 inline void Edge(int x, int y)
 59 {
 60     int a = Find(x), b = Find(y);
 61     if(a != b) fat[a] = b, si[b] += si[a];
 62     Ins(x, y), Ins(y, x);
 63 }
 64 int Add(int p, int l, int r, int v)
 65 {
 66     int k = ++cnt;
 67     sum[k] = sum[p] + 1;
 68     if(l == r) return k;
 69     int mi = l + r >> 1;
 70     if(v <= mi) lc[k] = Add(lc[p], l, mi, v), rc[k] = rc[p];
 71     else lc[k] = lc[p], rc[k] = Add(rc[p], mi + 1, r, v);
 72     return k;
 73 }
 74 void Build(int u, int f)
 75 {
 76     vis[u] = true;
 77     dep[u] = dep[f] + 1;
 78     anc[u][0] = f;
 79     for(int i = 1; i <= logn; ++i)
 80         anc[u][i] = anc[anc[u][i - 1]][i - 1];
 81     rt[u] = Add(rt[f], 1, num, val[u]);
 82     for(int i = fir[u]; i; i = nex[i])
 83     {
 84         int v = ver[i];
 85         if(v == f) continue;
 86         Build(v, u);
 87     }
 88 }
 89 inline void Edge()
 90 {
 91     for(int i = 1; i <= m; ++i) Edge(Get(), Get());
 92 }
 93 inline void Build()
 94 {
 95     for(int i = 1; i <= n; ++i)
 96         if(!vis[i])
 97             Build(i, 0);
 98 }
 99 inline void Link(int x, int y)
100 {
101     int a = Find(x), b = Find(y);
102     if(si[a] < si[b]) swap(x, y);
103     dep[y] = dep[x] + 1;
104     Build(y, x);
105     Ins(x, y), Ins(y, x);
106 }
107 inline int Lca(int x, int y)
108 {
109     if(dep[x] < dep[y]) swap(x, y);
110     for(int i = logn; i >= 0; --i)
111         if(dep[anc[x][i]] >= dep[y])
112             x = anc[x][i];
113     if(x == y) return x;
114     for(int i = logn; i >= 0; --i)
115         if(anc[x][i] != anc[y][i])
116         {
117             x = anc[x][i];
118             y = anc[y][i];
119         }
120     return anc[x][0];
121 }
122 inline int Query(int a, int b, int c, int d, int l, int r, int k)
123 {
124     if(l == r) return disp[l];
125     int res = sum[lc[a]] + sum[lc[b]] - sum[lc[c]] - sum[lc[d]];
126     int mi = l + r >> 1;
127     if(res >= k) return Query(lc[a], lc[b], lc[c], lc[d], l, mi, k);
128     return Query(rc[a], rc[b], rc[c], rc[d], mi + 1, r, k - res);
129 }
130 inline void Ask()
131 {
132     while(q--)
133     {
134         char c;
135         while((c = getchar()) != 'L' && c != 'Q');
136         switch(c)
137         {
138             case 'L':
139             {
140                 int x = Get() ^ ans, y = Get() ^ ans;
141                 Link(x, y);
142                 break;
143             }
144             case 'Q':
145             {
146                 int x = Get() ^ ans, y = Get() ^ ans, k = Get() ^ ans;
147                 int lca = Lca(x, y);
148                 ans = Query(rt[x], rt[y], rt[lca], rt[anc[lca][0]], 1, num, k);
149                 printf("%d\n", ans);
150                 break;
151             }
152         }
153     }
154 }
155 int main()
156 {
157     t = Get(), n = Get(), m = Get(), q = Get();
158     for(int i = 1; i <= n; ++i) val[i] = Get();
159     Reset();
160     Disperse();
161     Edge();
162     Build();
163     Ask();
164 }
posted @ 2017-03-25 11:31  草根柴鸡  阅读(180)  评论(0编辑  收藏  举报