Solution - 龙珠

描述

\(link\)
有标号为 \(1\) 到 \(n\) 的 \(n\) 个龙珠,分别放在对应标号为 \(1\) 到 \(n\) 的 \(n\) 个城市里。

下面有两种操作:
T A B 表示把 A 龙珠所在城市的所有龙珠都转移到 B 龙珠所在的城市中
Q A 表示查询 A ,需要知道 A 龙珠现在所在的城市,A 所在的城市有几颗龙珠,A 转移到这个城市移动了多少次,分别输出 \(3\) 个整数,表示上述信息。

题解

所在城市和移动次数在这里就不在赘述(学过并查集都会)

本题相对于普通的并查集多了一个转移次数这个东西,我们可以用懒惰标记(详见OI-WIKI - 线段树)的思想来记录。具体操作如下:

用 \(vis\) 来表示转移次数。显然,每个集合的代表转移次数为 \(0\)。执行T操作时,A集合的代表肯定的转移次数会变 \(1\),更新成员的转移次数时,只用加上其父亲的 \(vis\) 值即可。

\(code\)

#include <bits/stdc++.h>
using namespace std;
int n, m;
char c;
int father[10005];
int cnt[10005];
int vis[10005];
int a, b;
void init() {
	for (int i = 1; i <= n; i++) father[i] = i, cnt[i] = 1, vis[i] = 0;
}
int find(int x) {
	if (x == father[x]) {
		return x;
	} else {
		int t = find(father[x]);
		vis[x] += vis[father[x]];
		return father[x] = t;
	}
} 
inline void read(int &a) {
    a = 0;
    bool f = false;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')
            f = true;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        a = (a << 1) + (a << 3) + c - '0';
        c = getchar();
    }
    if (f) a *= -1;
}
inline void write(int x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x < 10) {
        putchar(x + '0');
        return;
    }
    write(x / 10);
    putchar(x % 10 + '0');
}
int main() {
	int t;
	read(t);
	for (int i = 1; i <= t; i++) {
		read(n), read(m);
		init();
		printf("Case %d:\n", i);
		for (int i = 1; i <= m; i++) {
			c = getchar();
			if (c == 'T') {
				read(a), read(b);
				int x = find(a), y = find(b);
				if (x == y) continue;
				father[x] = y;
				cnt[y] += cnt[x];
				cnt[x] = 0;
				vis[x] = 1;
			} else if (c == 'Q') {
				read(a);
				write(find(a));
				putchar(' ');
				write(cnt[find(a)]);
				putchar(' ');
				find(a);
				write(vis[a]);
				putchar('\n');
			}
		}
	}
	return 0;
} 
上一篇:Solution - 生日蛋糕


下一篇:基础算法-斐波那契