luoguP3224 [HNOI2012]永無鄉
阿新 • • 發佈:2018-08-27
show n) noi2012 || roo namespace -- oid clu
https://www.luogu.org/problemnew/show/P3224
考慮對每個島維護一顆平衡樹,用並查集維護連通性,啟發式合並即可
這東西其實是一個大暴力,每次把節點少的平衡樹合並到節點多的平衡樹裏
這樣可以保證每個點合並一次樹的大小*2,每個點最多被插入 log(n) 次,復雜度正確
我使用了簡單好寫的 leafy tree 作為平衡樹,不喜勿噴
#include <bits/stdc++.h> #define update(u) if(u -> left -> size) u -> size = u -> left -> size + u -> right -> size, u -> value = u -> right -> value #define new_Node(a, b, c, d) (&(*st[cnt++] = Node(a, b, c, d))) #define merge(a, b) new_Node(a -> size + b -> size, b -> value, a, b) #define ratio 4 using namespace std; typedef unsigned long long ull; typedef long long ll; template <typename _T> inline void read(_T &f) { f = 0; _T fu = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') fu = -1; c = getchar();} while(c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + (c & 15); c = getchar();} f *= fu; } const int N = 300000 + 10; struct Node { int size, value; Node *left, *right; Node (int a, int b, Node *c, Node *d) : size(a), value(b), left(c), right(d) {} Node () {} }*root[N], *st[N], t[N], *null; int w[N], v[N], f[N], pre[N], len; int n, m, q, cnt = 0; void maintain(Node *u) { if(u -> left -> size > u -> right -> size * ratio) u -> right = merge(u -> left -> right, u -> right), st[--cnt] = u -> left, u -> left = u -> left -> left; if(u -> right -> size > u -> left -> size * ratio) u -> left = merge(u -> left, u -> right -> left), st[--cnt] = u -> right, u -> right = u -> right -> right; } void ins(Node *u, int x) { if(u -> size == 1) u -> left = new_Node(1, min(u -> value, x), null, null), u -> right = new_Node(1, max(u -> value, x), null, null); else ins(x > u -> left -> value ? u -> right : u -> left, x); update(u); maintain(u); } int find(Node *u, int x) { if(u -> size == 1) return u -> value; return x > u -> left -> size ? find(u -> right, x - u -> left -> size) : find(u -> left, x); } void dfs(Node *u) { if(u == null) return; st[--cnt] = u; dfs(u -> left); if(u -> size == 1) w[++len] = u -> value; dfs(u -> right); } int Merge(int a, int b) { if(root[a] -> size < root[b] -> size) swap(a, b); len = 0; dfs(root[b]); for(register int i = 1; i < len; i++) { ins(root[a], w[i]); } return a; } int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); } int main() { read(n); read(m); null = new Node(0, 0, 0, 0); for(register int i = 0; i <= 300000; i++) st[i] = &t[i]; for(register int i = 1; i <= n; i++) root[i] = new Node(1, INT_MAX, null, null), read(v[i]), ins(root[i], v[i]), f[i] = i, pre[v[i]] = i; for(register int i = 1; i <= m; i++) { int a, b; read(a); read(b); int x = find(a), y = find(b); if(x == y) continue; int fa = Merge(x, y); f[x] = f[y] = fa; } read(q); for(register int i = 1; i <= q; i++) { char c = getchar(); while(c != 'Q' && c != 'B') c = getchar(); if(c == 'Q') { int a, b; read(a); read(b); int x = find(a); if(root[x] -> size - 1 < b) { printf("-1\n"); continue; } printf("%d\n", pre[find(root[x], b)]); } else { int a, b; read(a); read(b); int x = find(a), y = find(b); if(x == y) continue; int fa = Merge(x, y); f[x] = f[y] = fa; } } return 0; }
luoguP3224 [HNOI2012]永無鄉