UVA - 11987 Almost Union-Find

Description

洛谷翻译

注意:操作 \(3\) 并没有要求查询后从其所在集合里删除该元素。

Solution

因为有操作 \(2\),我们给每个点建一个虚点,用来表示集合来维护答案。普通的点初始就认对应集合为爸爸,然后普通的点就可以随便移动了。

Code

#include <cstdio>

const int N = 1e5 + 5;

int n, m, f[N], cnt[N];
long long ans[N];

int read() {
    int x = 0, f = 1; char s;
    while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
    return x * f;
}

int Find(const int x) {return x == f[x] ? x : f[x] = Find(f[x]);}

void init() {for(int i = 1; i <= n; ++ i) f[i] = n + i, f[n + i] = n + i, cnt[n + i] = 1, ans[n + i] = i;}

int main() {
    int op, x, y, u, v;
    while(~ scanf("%d %d", &n, &m)) {
        init();
        while(m --) {
            op = read();
            if(op == 1) {
                x = read(), y = read();
                u = Find(x), v = Find(y);
                if(u == v) continue;
                ans[v] += ans[u]; cnt[v] += cnt[u]; f[u] = v;
            }
            else if(op == 2) {
                x = read(), y = read();
                u = Find(x), v = Find(y);
                f[x] = v;
                -- cnt[u]; ++ cnt[v];
                ans[u] -= x, ans[v] += x;
            }
            else {
                x = Find(read());
                printf("%d %lld\n", cnt[x], ans[x]);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AWhiteWall/p/12926295.html