[kuangbin带你飞] 专题1-23 https://vjudge.net/article/187
专题五 并查集
√ POJ 2236 Wireless Network http://poj.org/problem?id=2236
√ POJ 1611 The Suspects http://poj.org/problem?id=1611
√ HDU 1213 How Many Tables http://acm.hdu.edu.cn/showproblem.php?pid=1213
hdu炸了。 HDU 3038 How Many Answers Are Wrong http://acm.hdu.edu.cn/showproblem.php?pid=3038
√ POJ 1182 食物链 http://poj.org/problem?id=1182
POJ 1417 True Liars http://poj.org/problem?id=1417
√ POJ 1456 Supermarket http://poj.org/problem?id=1456
√ POJ 1733 Parity game http://poj.org/problem?id=1733
√ POJ 1984 Navigation Nightmare http://poj.org/problem?id=1984
√ POJ 2492 A Bug's Life http://poj.org/problem?id=2492
√ POJ 2912 Rochambeau http://poj.org/problem?id=2912
ZOJ 3261 Connections in Galaxy War http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
√ HDU 1272 小希的迷宫 http://acm.hdu.edu.cn/showproblem.php?pid=1272
√ POJ 1308 Is It A Tree? http://poj.org/problem?id=1308
// 种类并查集
// 种类并查集关系数组的向量偏移量 理解↓
// 图片来源 https://blog.csdn.net/u010660276/article/details/24851367
poj 2492 A Bug's Life http://poj.org/problem?id=2492
// 题意:每次给出两个昆虫的关系(异性关系),然后发现这些条件中是否有悖论
如 :input
1 2
2 3
1 3 ->错的
1 #include2 3 const int MAXN = 2000+5; 4 5 int fa[MAXN], re[MAXN];// re[i] 存 i和他根节点的关系 0为同性 1为异性 6 7 inline int find(int x) { 8 if(x != fa[x]) { 9 int t = fa[x]; 10 fa[x] = find(fa[x]); 11 re[x] = (re[x] + re[t]) % 2;// 更新x与根节点的关系 12 } 13 return fa[x]; 14 } 15 16 int main() { 17 int T; 18 int cnt = 0; 19 scanf("%d", &T); 20 while(T--) { 21 int n, m; 22 int x, y; 23 bool flag = true; 24 scanf("%d%d", &n, &m); 25 for(int i = 1; i <= n; ++i) { fa[i] = i; re[i] = 0; } 26 for(int i = 0; i != m; ++i) { 27 scanf("%d%d", &x, &y); 28 if(!flag) continue; 29 int x_fa = find(x); 30 int y_fa = find(y); 31 if(x_fa != y_fa) { 32 fa[x_fa] = y_fa; 33 re[x_fa] = (-re[x] + 1 + re[y] + 2) % 2;// 此处和37行中加2 都是为了消除0的影响
36 } 37 else if((re[x] - re[y] + 2) % 2 == 0) flag = false; 38 } 39 printf("Scenario #%d:\n", ++cnt); 40 if(flag) printf("No suspicious bugs found!\n\n"); 41 else printf("Suspicious bugs found!\n\n"); 42 } 43 return 0; 44 }
// 同理给出poj 1182 代码
1 #include2 #include 3 using namespace std; 4 5 const int MAXN = 50000+5; 6 7 int fa[MAXN], re[MAXN]; 8 9 inline int find(int x) { 10 if(x != fa[x]) { 11 int t = fa[x]; 12 fa[x] = find(fa[x]); 13 re[x] = (re[x] + re[t]) % 3; 14 } 15 return fa[x]; 16 } 17 18 int main() { 19 int n, k; 20 int ans = 0; 21 scanf("%d%d", &n, &k); 22 for(int i = 1; i <= MAXN; ++i) { fa[i] = i; re[i] = 0; } 23 24 int com; 25 int x, y; 26 int xf, yf; 27 for(int i = 0; i != k; ++i) { 28 scanf("%d%d%d", &com, &x, &y); 29 if(x > n || y > n || com == 2 && x == y) { ans++; continue; } 30 xf = find(x); 31 yf = find(y); 32 if(xf != yf) { 33 fa[xf] = yf; 34 re[xf] = (-re[x] + com-1 + re[y] + 3) % 3; 35 } 36 else if((re[x] - re[y] + 3) % 3 != com - 1) ans++; 37 } 38 printf("%d\n", ans); 39 return 0; 40 }
// 区间种类并查集
// poj1733 http://poj.org/problem?id=1733
// 有n个结点,给出了m个操作,操作是 a b com 表示结点a到结点b的和是奇数或偶数,输出前多少个操作是正确的
// n <= 1000000000; m <= 5000
// n 很大 m不大 由于有用的数据只是询问给出的 所以与n关系不大,所以离散化--没询问的点不管他(因为数组可能也开不到1000000000)
1 #include2 #include 3 #include
//奇葩并查集 poj 1984 http://poj.org/problem?id=1984
//此题 输入输出比较恶心 我英语不好只能瞎猜题意
1 #include2 #include 3 #include 4 using namespace std; 5 const int MAXN = 40000+5; 6 7 struct Query { 8 int x, y, id;// 存询问的列表(输入进去的东西) 9 int dis;// x与y之间的距离 10 int no;// 第几个输入的(输出要按输入顺序输出) 11 } q[10005] ; 12 13 int fa[MAXN], re[MAXN][2];// 带权并查集 [][2]是为了存x方向和y方向 14 int l[MAXN], r[MAXN], v[MAXN];// 输入的三个参数 15 char c[MAXN];// 输入的方向(N S W E) 16 17 inline int find(int x) { 18 if(x != fa[x]) { 19 int t = fa[x]; 20 fa[x] = find(fa[x]); 21 re[x][0] += re[t][0]; 22 re[x][1] += re[t][1]; 23 } 24 return fa[x]; 25 } 26 27 bool cmp(const Query a, const Query b) { 28 return a.id < b.id; 29 } 30 31 bool cmp2(const Query a, const Query b) { 32 return a.no < b.no; 33 } 34 35 int main() { 36 int n, m; 37 scanf("%d%d", &n, &m); 38 for(int i = 1; i <= n; ++i) { fa[i] = i; re[i][0] = re[i][1] = 0; } 39 for(int i = 0; i != m; ++i) { 40 scanf("%d%d%d", &l[i], &r[i], &v[i]); 41 getchar(); scanf("%c", &c[i]); 42 } 43 int k; 44 scanf("%d", &k); 45 for(int i = 0; i != k; ++i) { 46 scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].id); 47 q[i].no = i; 48 } 49 sort(q, q+k, cmp); 50 int x, y; 51 int xf, yf; 52 char com; 53 int t = 0; 54 for(int i = 0; i != m; ++i) { 55 x = l[i]; y = r[i]; com = c[i]; 56 xf = find(x); 57 yf = find(y); 58 if(xf != yf) { 59 fa[xf] = yf; 60 re[xf][0] = -re[x][0] + re[y][0]; 61 re[xf][1] = -re[x][1] + re[y][1]; 62 if(com == 'N') { re[xf][0] += 0; re[xf][1] += v[i]; } 63 if(com == 'S') { re[xf][0] += 0; re[xf][1] += -v[i]; } 64 if(com == 'W') { re[xf][0] += -v[i]; re[xf][1] += 0; } 65 if(com == 'E') { re[xf][0] += v[i]; re[xf][1] += 0; } 66 } 67 while(i+1 == q[t].id) {// 必须用while (Bob询问的时候可能同一时间段问几个问题) 68 if(find(q[t].x) != find(q[t].y)) q[t].dis = -1; 69 else q[t].dis = abs(re[q[t].x][0] - re[q[t].y][0]) + abs(re[q[t].x][1] - re[q[t].y][1]); 70 t++; 71 } 72 } 73 sort(q, q+k, cmp2); 74 for(int i = 0; i != k; ++i) { 75 printf("%d\n", q[i].dis); 76 } 77 return 0; 78 }
// poj 2912 关系并查集+枚举 http://poj.org/problem?id=2912
1 #include2 #include 3 #include<set> 4 using namespace std; 5 6 const int MAXN = 500+5; 7 8 int fa[MAXN], re[MAXN]; 9 int l[4*MAXN], r[4*MAXN], com[4*MAXN]; 10 11 inline int find(int x) { 12 if(x != fa[x]) { 13 int t = fa[x]; 14 fa[x] = find(fa[x]); 15 re[x] = (re[x] + re[t]) % 3; 16 } 17 return fa[x]; 18 } 19 20 int main() { 21 int n, m; 22 while(scanf("%d%d", &n, &m) == 2) { 23 char ch[2*MAXN]; 24 for(int i = 0; i != m; ++i) { l[i] = r[i] = 0; } 25 for(int i = 0; i != m; ++i) { 26 scanf("%s", ch); 27 int j = 0; 28 while(ch[j] >= '0' && ch[j] <= '9') { 29 l[i] = l[i]*10 + ch[j]-'0'; 30 j++; 31 } 32 if(ch[j] == '=') com[i] = 0; 33 else if(ch[j] == '>') com[i] = 1; 34 else com[i] = 2; 35 j++; 36 while(ch[j] != '\0') { 37 r[i] = r[i]*10 + ch[j]-'0'; 38 j++; 39 } 40 } 41 int x, y; 42 int xf, yf; 43 int c; 44 int pos = 0; 45 set<int> ct; 46 for(int k = 0; k != n; ++k) { 47 bool flag = true; 48 int cnt = 0; 49 for(int qwq = 0; qwq != n; ++qwq) { fa[qwq] = qwq; re[qwq] = 0; } 50 for(int i = 0; i != m; ++i) { 51 if(l[i] == k || r[i] == k) continue; 52 x = l[i]; y = r[i]; c = com[i]; 53 xf = find(x); 54 yf = find(y); 55 if(xf != yf) { 56 fa[xf] = yf; 57 re[xf] = (-re[x] + c + re[y] + 3) % 3; 58 } 59 else if((re[x] - re[y] + 3) % 3 != c) { 60 flag = false; 61 pos = max(pos, i+1);// 想不到这个(排除法 有一个裁判且其他人都不是裁判的时候 就能确定他是裁判) 62 break; 63 } 64 } 65 if(flag) ct.insert(k); 66 } 67 if(ct.size() == 0) printf("Impossible\n"); 68 else if(ct.size() == 1) { 69 int t = *ct.begin(); 70 printf("Player %d can be determined to be the judge after %d lines\n", t, pos); 71 } 72 else printf("Can not determine\n"); 73 } 74 return 0; 75 }
//poj 1456 贪心(这题并查集优化完全没必要)http://poj.org/problem?id=1456
1 #include2 #include 3 #include 4 using namespace std; 5 6 const int MAXN = 10000+5; 7 8 struct Product { 9 int v, r; 10 } p[MAXN]; 11 12 bool cmp(const Product a, const Product b) { 13 if(a.v != b.v) return a.v > b.v; 14 return a.r > b.r; 15 } 16 17 int fa[MAXN]; 18 inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } 19 20 inline void init() { 21 for(int i = 0; i != MAXN; ++i) { 22 fa[i] = i; 23 } 24 } 25 int n; 26 int ans; 27 28 int main() { 29 while(scanf("%d", &n) == 1) { 30 for(int i = 0; i != n; ++i) { 31 scanf("%d%d", &p[i].v, &p[i].r); 32 } 33 sort(p, p+n, cmp); 34 ans = 0; 35 init(); 36 for(int i = 0; i != n; ++i) { 37 int d = p[i].r; 38 int x = find(d); 39 if(x > 0) { 40 fa[x] = x-1; 41 ans += p[i].v; 42 } 43 } 44 printf("%d\n", ans); 45 } 46 return 0; 47 }
// hdu 1272 & poj 1308
// "求树是否是个环"(简单并查集) ,水。
1 #include2 #include 3 using namespace std; 4 5 const int MAXN = 1e3+5; 6 7 inline int read() { 8 char c = getchar(); int s = 0, f = 1; 9 while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } 10 while(c >= '0' && c <= '9') s = s*10 + c-'0', c = getchar(); 11 return s*f; 12 } 13 14 int p[MAXN]; 15 16 inline int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } 17 18 int main() { 19 int s, e; 20 int T = 1; 21 while(1) { 22 bool flag = true; 23 while(1) { //scanf("%d%d", &s, &e) == 2 && s 24 s = read(), e = read(); 25 if(s == 0 && e == 0) break; 26 if(s == -1) return 0; 27 if(!p[s]) p[s] = s; 28 if(!p[e]) p[e] = e; 29 int x = find(s); 30 int y = find(e); 31 if(x == y) flag = false; 32 else p[x] = y; 33 } 34 int ans = 0; 35 for(int i = 1; i <= MAXN; ++i) { 36 if(p[i] == i) ans++; 37 p[i] = 0; 38 } 39 40 printf("Case %d is ", T++); 41 if(!flag || ans > 1) printf("not a tree.\n"); 42 else printf("a tree.\n"); 43 } 44 return 0; 45 }
// poj 2236 简单并查集 水。
1 #include2 #include 3 #include 4 using namespace std; 5 6 const int MAXN = 1000+5; 7 8 struct node { 9 double x, y; 10 int fa; 11 bool repair; 12 } p[MAXN]; 13 14 inline double get_dis(int x, int y) { 15 return sqrt((p[x].x-p[y].x)*(p[x].x-p[y].x) + (p[x].y-p[y].y)*(p[x].y-p[y].y)); 16 } 17 18 inline int find(int x) { return p[x].fa == x ? x : p[x].fa = find(p[x].fa); } 19 20 int main() { 21 int n, d; 22 scanf("%d%d", &n, &d); 23 for(int i = 1; i <= n; ++i) { 24 scanf("%lf%lf", &p[i].x, &p[i].y); 25 p[i].fa = i; 26 p[i].repair = false; 27 } 28 getchar(); 29 char c; 30 while(scanf("%c", &c) == 1) { 31 if(c == 'O') { 32 int x; 33 scanf("%d", &x); 34 for(int i = 1; i <= n; ++i) { 35 if(p[i].repair) { 36 if(get_dis(i, x) <= d*1.0) { 37 int xf = find(x); 38 int yf = find(i); 39 if(xf != yf) p[xf].fa = yf; 40 } 41 } 42 } 43 p[x].repair = true; 44 } 45 else { 46 int x, y; 47 scanf("%d%d", &x, &y); 48 if(find(x) == find(y)) printf("SUCCESS\n"); 49 else printf("FAIL\n"); 50 } 51 getchar(); 52 } 53 return 0; 54 }
// poj 1611 简单并查集 水。
1 #include2 #include 3 using namespace std; 4 5 const int MAXN = 3e4+5; 6 7 int p[MAXN]; 8 inline int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } 9 10 int main() { 11 int n, m; 12 while(scanf("%d%d", &n, &m) == 2 && n) { 13 memset(p, -1, sizeof(p)); 14 p[0] = 0; 15 for(int i = 0; i != m; ++i) { 16 int num, x, t; 17 scanf("%d", &num); 18 for(int j = 0; j != num; ++j) { 19 scanf("%d", &x); 20 if(p[x] == -1) p[x] = x; 21 if(j != 0) { 22 int xf = find(x); 23 int tf = find(t); 24 if(xf != tf) p[xf] = tf; 25 } 26 t = x; 27 } 28 } 29 int ans = 0; 30 for(int i = 0; i != n; ++i) { 31 //printf("%d\n", find(i)); 32 if(p[i] != -1 && find(i) == find(0)) ans++; 33 } 34 printf("%d\n", ans); 35 } 36 return 0; 37 }
// poj 1988 带权并查集入门题 http://poj.org/problem?id=1988
1 #include2 #include 3 using namespace std; 4 5 const int MAXN = 30000+5; 6 7 int fa[MAXN], dis[MAXN], sum[MAXN]; 8 9 inline int find(int x) { 10 if(x != fa[x]) { 11 int t = fa[x]; 12 fa[x] = find(fa[x]); 13 dis[x] += dis[t]; 14 } 15 return fa[x]; 16 } 17 18 inline void Union(int x, int y) { 19 x = find(x); 20 y = find(y); 21 if(x != y) { 22 fa[x] = y; 23 dis[x] = sum[y]; 24 sum[y] += sum[x]; 25 } 26 } 27 28 int main() { 29 int n, x, y; 30 char c; 31 scanf("%d", &n); 32 for(int i = 0; i != MAXN; ++i) { 33 fa[i] = i; 34 dis[i] = 0; 35 sum[i] = 1; 36 } 37 for(int i = 0; i != n; ++i) { 38 getchar(); 39 scanf("%c", &c); 40 if(c == 'M') { 41 scanf("%d%d", &x, &y); 42 Union(x, y); 43 } 44 else { 45 scanf("%d", &x); 46 find(x); 47 printf("%d\n", dis[x]); 48 } 49 } 50 return 0; 51 }