1. 程式人生 > >luoguP3224 [HNOI2012]永無鄉

luoguP3224 [HNOI2012]永無鄉

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]永無鄉