合纵连横
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。
有两种操作
1、U x y 表示x和y在同一个联盟。(0≤x,y<n)
2、D x 表示x退出联盟。
-
输入
-
多组测试数据
第一行两个数,n和m(1 ≤ n≤ 10^5, 1 ≤ m ≤10^5),分别表示诸侯国的个数和操作次数。
接下来有m行操作
输出
- 输出联盟的个数 样例输入
-
5 7 U 0 1 U 1 2 U 0 3 D 0 U 1 4 D 2 U 0 2 10 1 U 0 9
样例输出
-
Case #1: 2
Case #2: 9
-
-
前天刚看过并查集的删除,听队友说南阳有一道。就来做了一下。
-
避免去掉根节点时影响到子节点,对N个点建立映射即每个点的根节点当作节点编号+N,对于合并的节点正常处理;对于删除的节点,只需把它的根节点更新为一个新的值即可。
-
AC代码:
-
-
#include <cstdio> #include <cstring> #define MAXN 300000 int set[MAXN]; bool vis[MAXN]; int N, M; int num;//记录编号 int k = 1; int find(int p) { int t; int child = p; while(p != set[p]) p = set[p]; while(child != p) { t = set[child]; set[child] = p; child = t; } return p; } void merge(int x, int y) { int fx = find(x); int fy = find(y); if(fx != fy) set[fx] = fy; } void init()//注意初始化 { for(int i = 0; i < N; i++) set[i] = i + N;//避免去掉根节点时 影响到其他节点 for(int i = N; i < N+N+M; i++) set[i] = i; } void input() { int x, y; char op[5]; num = N + N; while(M--) { scanf("%s", op); switch(op[0]) { case 'U': scanf("%d%d", &x, &y); merge(x, y); break; case 'D': scanf("%d", &x); set[x] = num++; } } } void solve() { int ans = 0; memset(vis, false, sizeof(vis)); printf("Case #%d: ", k++); for(int i = 0; i < N; i++) { if(!vis[find(i)]) { ans++; vis[find(i)] = true; } } printf("%d\n", ans); } int main() { while(scanf("%d%d", &N, &M) != EOF) { init(); input(); solve(); } return 0; }
-
多组测试数据