思路:关键在于并查集的删点操作。 给每个诸侯国一个另外的编号,比如box[i]表示诸侯国i现在处于第box[i]个联盟,可以随时改变它的联盟编号,并且让box[i] = k, 实现删除操作。以前联盟中的那个点是一个虚点,只是帮助子节点找到根结点。查找时通过联盟编号查询。
AC代码
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 100000 + 5; int p[maxn<<1], box[maxn], vis[maxn<<1]; int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } void unionset(int x, int y) { int px = find(box[x]), py = find(box[y]); if(px != py) p[px] = py; } int cur; void del(int x) { //删点 box[x] = cur++; p[box[x]] = box[x]; } int main() { int n, m, kase = 1; while(scanf("%d%d", &n, &m) == 2) { cur = n; for(int i = 0; i < n; ++i) { p[i] = i; box[i] = i; } int x, y; char ch; for(int i = 0; i < m; ++i) { getchar(); scanf("%c", &ch); if(ch == 'U') { scanf("%d%d", &x, &y); unionset(x, y); } else { scanf("%d", &x); del(x); } } memset(vis, 0, sizeof(vis)); for(int i = 0; i < n; ++i) { vis[find(box[i])] = 1; } int ans = 0; for(int i = 0; i < cur; ++i) { if(vis[i]) ++ans; } printf("Case #%d: %d\n", kase++, ans); } return 0; }
如有不当之处欢迎指出!