【洛谷 P3224】 [HNOI2012]永无乡(Splay,启发式合并)

题目链接
启发式合并就是暴力合并把小的合并到大的里,一个一个插进去。
并查集维护连通性,同时保证并查集的根就是所在Splay的根,这样能省去很多操作。

#include <cstdio>
#include <algorithm>
using namespace std;
inline int read(){
    int s = 0, w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
const int MAXN = 100010;
struct SplayTree{
    int ch[2], fa, val, size;
}t[MAXN];
int num, root, n, m, f[MAXN];
int find(int x){
    return f[x] == x ? x : f[x] = find(f[x]);
}
void pushup(int u){
    t[u].size = t[t[u].ch[0]].size + t[t[u].ch[1]].size + 1;
}
void rotate(int x){
    int y = t[x].fa;
    int z = t[y].fa;
    int k = t[y].ch[1] == x;
    t[z].ch[t[z].ch[1] == y] = x;
    t[x].fa = z;
    t[y].ch[k] = t[x].ch[k ^ 1];
    t[t[x].ch[k ^ 1]].fa = y;
    t[x].ch[k ^ 1] = y;
    t[y].fa = x;
    pushup(y);
    pushup(x);
}
void Splay(int x, int goal){
    while(t[x].fa){
      int y = t[x].fa, z = t[y].fa;
      if(z)
   /**/ (t[z].ch[0] == y) ^ (t[y].ch[0] == x) ? rotate(x) : rotate(y);
        rotate(x);
    }
    if(goal == 0) root = x;
}
inline int findKth(int k){
    int u = root;
    while(1){
      if(t[t[u].ch[0]].size >= k) u = t[u].ch[0];
      else if(t[t[u].ch[0]].size == k - 1) return u;
      else k -= t[t[u].ch[0]].size + 1, u = t[u].ch[1];
    }
}
int next(int x, int mode){
    int u = t[x].ch[mode];
    while(t[u].ch[!mode]) u = t[u].ch[!mode];
    return u;
}
int a, b;
char c;
void insert(int x){
    int u = root, fa = 0;
    while(u) fa = u, u = t[u].ch[t[x].val > t[u].val];
    t[fa].ch[t[x].val > t[fa].val] = x;
    t[x].fa = fa;
    Splay(x, 1);
}
void merge(int u){
    if(t[u].ch[0]) merge(t[u].ch[0]); 
    if(t[u].ch[1]) merge(t[u].ch[1]);
    t[u].ch[0] = t[u].ch[1] = 0; insert(u);
}
int T;
int main(){
    n = read(); m = read();
    for(int i = 1; i <= n; ++i)
       t[i].val = read(), t[i].size = 1, f[i] = i;
    for(int i = 1; i <= m; ++i){
       a = read(); b = read();
       int x = find(a), y = find(b);
       if(x == y) continue;
       if(t[x].size > t[y].size){
           f[y] = x;
           root = x; merge(y); Splay(x, 0);
       }
       else{
           f[x] = y;
           root = y; merge(x); Splay(y, 0);
       }
    }
    T = read();
    for(int i = 1; i <= T; ++i){
       c = getchar(); while(c != 'Q' && c != 'B') c = getchar();
       a = read(); b = read();
       if(c == 'B'){
         int x = find(a), y = find(b);
         if(x == y) continue;
         if(t[x].size > t[y].size){
             f[y] = x;
             root = x; merge(y); Splay(x, 0);
         }
         else{
             f[x] = y;
             root = y; merge(x); Splay(y, 0);
         }
       }
       else{
         root = find(a);
         if(t[root].size < b) printf("%d\n", -1);
         else printf("%d\n", findKth(b));
       }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Qihoo360/p/10807516.html