神奇的并查集,是我最开始学会的除了数组的数据结构...
真的是一个优美的数据结构啊啊啊啊!!!
poj p1703
像那道“关押罪犯”,拆点就好了
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5
6 const int maxn = 1e5 + 10;
7
8 char buff[3];
9 int Tcase, n, m, f[maxn * 2];
10
11 int find(int x){
12 return x == f[x] ? x : f[x] = find(f[x]);
13 }
14
15 int main(){
16 int x, y;
17 scanf("%d", &Tcase);
18 while (Tcase --){
19 scanf("%d %d", &n, &m);
20 for (int i = 1; i <= n * 2; i ++)
21 f[i] = i;
22
23 for (int i = 0; i < m; i ++){
24 scanf("%s %d %d", buff, &x, &y);
25 if (buff[0] == 'A'){
26 if (find(x) == find(y + n) || find(x + n) == find(y))
27 puts("In different gangs.");
28 else if (find(x) == find(y) || find(x + n) == find(y + n))
29 puts("In the same gang.");
30 else
31 puts("Not sure yet.");
32 }
33
34 else
35 f[find(x)] = find(y + n), f[find(x + n)] = find(y);
36 }
37 }
38 }
tyvj P1017 冗余关系
当年刚刚学会并查集,合并写的是rank(),ce了好多次
tyvj p1017
tyvj P1220 微子危机——建造
tyvj p1220
tyvj P1242 Fated Me's Power
1 #include <cmath>
2 #include <cstdio>
3 #include <algorithm>
4 using namespace std;
5
6 const int maxn = 4000 + 10;
7
8 int n, m, lyd, f[maxn];
9
10 int find(int x){
11 return x == f[x] ? x : f[x] = find(f[x]);
12 }
13
14 bool _(int x){
15 if (x == 1)
16 return false;
17
18 for (int i = 2; i <= sqrt(x); i ++)
19 if (x % i == 0)
20 return false;
21
22 return true;
23 }
24
25 int main(){
26 scanf("%d %d", &n, &m);
27
28 for (int i = 1; i <= n; i ++)
29 f[i] = i;
30
31 int a, b, fa, fb;
32 while (m --){
33 scanf("%d %d", &a, &b);
34 fa = find(a), fb = find(b);
35 if (fa != fb)
36 f[fa] = fb;
37 }
38
39 scanf("%d", &lyd);
40
41 int flyd = find(lyd);
42 a = b = 0;
43 for (int i = 1; i <= n; i ++)
44 if (flyd == find(i)){
45 if (_(i))
46 a ++;
47 else
48 b ++;
49 }
50
51 printf("%d\n", min(a, b));
52 }
tyvj P1251 家族
tyvj p1251
tyvj P1252 小胖的奇偶
论选择一个好的hash值得重要性...
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5
6 const int mod = 100007;
7 const int maxn = 300000;
8 const int maxm = 10000 + 10;
9
10 char buff[10];
11 int n, m, hash[mod + 2], len[maxn + 2], f[maxn + 2];
12
13 inline int get_hash(int x){
14 int ret = x % mod;
15 while (hash[ret] ^ -1 && hash[ret] ^ x)
16 ret = (ret + 1) % mod;
17
18 hash[ret] = x;
19
20 return ret;
21 }
22
23 inline int find(int x){
24 if (f[x] ^ x){
25 int temp = f[x];
26 f[x] = find(temp);
27 len[x] = (len[x] + len[temp] + 2) & 1;
28 }
29
30 return f[x];
31 }
32
33 inline bool legal(int a, int b, int type){
34 int fa = find(a), fb = find(b), temp = len[a] - len[b] + 2;
35
36 if (fa ^ fb){
37 //link a and b
38 f[fb] = fa, len[fb] = (temp + type) & 1;
39 return true;
40 }
41
42 else if ((temp & 1) ^ type)
43 return false;
44
45 return true;
46 }
47
48 int main(){
49 memset(hash, -1, sizeof hash);
50
51 scanf("%d %d", &n, &m);
52
53 for (int i = 1; i <= maxn; i ++)
54 f[i] = i;
55
56 for (int i = 1, l, r, type; i <= m; i ++){
57 scanf("%d %d %s", &l, &r, buff);
58 type = buff[0] == 'o';
59
60 if (!legal(get_hash(l - 1), get_hash(r), type)){
61 printf("%d\n", i - 1);
62 return 0;
63 }
64 }
65
66 printf("%d\n", m);
67 }
tyvj P1323 识别水果
字符串...并且我是用图做的...不要问我为什么我要放在这..
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5
6 const int maxl = 26 + 10;
7 const int maxn = 10000 + 10;
8 const char T[maxl] = "poison";
9
10 int n, m, q, ne = 0;
11 bool p[maxn], vis[maxn];
12 char a[maxl], b[maxl], c[maxl], s[maxl * 3];
13
14 struct Edge {
15 int to;
16 Edge *next;
17 } *head[maxn], e[maxn * 10];
18
19 void add_edge(int f, int to){
20 e[ne].to = to;
21 e[ne].next = head[f];
22 head[f] = e + ne ++;
23 }
24
25 bool match(int st){
26 for (int i = st, j = 0; j < 6; i ++, j ++)
27 if (s[i] != T[j])
28 return false;
29
30 return true;
31 }
32
33 bool check(){
34 int len = strlen(s);
35
36 for (int i = 0; i < len; i ++)
37 s[i] = c[s[i] - 'a'];
38
39 for (int i = 0; i <= len - 6; i ++)
40 if (match(i))
41 return true;
42
43 return false;
44 }
45
46 void dfs(int now){
47 vis[now] = true;
48 for (Edge *p = head[now]; p; p = p->next)
49 if (!vis[p->to])
50 dfs(p->to);
51 }
52
53 int main(){
54 memset(p, false, sizeof p);
55 memset(vis, false, sizeof vis);
56
57 scanf("%s %s %d %d", a, b, &n, &m);
58
59 for (int i = 0; i < 26; i ++)
60 c[a[i] - 'a'] = b[i];
61
62 int v, u, id, ans = 0;
63 for (int i = 0; i < m; i ++){
64 scanf("%d %s", &id, s);
65 if (check())
66 p[id] = true;
67 }
68
69 scanf("%d", &q);
70 for (int i = 0; i < q; i ++){
71 scanf("%d %d", &u, &v);
72 add_edge(u, v);
73 add_edge(v, u);
74 }
75
76 for (int i = 1; i <= n; i ++)
77 if (p[i] && !vis[i])
78 dfs(i);
79
80 for (int i = 1; i <= n; i ++)
81 if (!vis[i])
82 ans ++;
83
84 printf("%d\n", ans);
85 }
tyvj P1438 [NOI2001]食物链
拆点或者加权,由于比较蠢,就只写了拆点的(同类、吃、被吃)
1 #include <cstdio>
2
3 const int MAXN = 50000*3+10;
4
5 int ans,n,m,f[MAXN];
6
7 inline int find(int x){
8 return (f[x]==x) ? x : f[x]=find(f[x]);
9 }
10
11 inline void link(int x,int y){
12 f[find(x)] = find(y);
13 }
14
15 inline int cal(){
16 int a1,a2,a3,b1,b2,b3,a,b,d;
17 scanf("%d %d %d",&d,&a,&b);
18 if ((d==2 && a==b) || a>n || b>n) return 1;
19 a1 = find(a),a2 = find(a+n),a3 = find(a+n+n);
20 b1 = find(b),b2 = find(b+n),b3 = find(b+n+n);
21
22 if (d==1 && a1!=b3 && a1!=b2 && b1!=a2 && b1!=b3){
23 link(a,b),link(a+n,b+n),link(a+n+n,b+n+n);
24 return 0;
25 }
26 if (d==1) return 1;
27 if (d==2 && a1!=b1 && a2!=b1 && b3!=a1){
28 link(a,b2),link(a3,b1),link(a2,b3);
29 return 0;
30 }
31 return 1;
32 }
33
34 int main(){
35 scanf("%d%d",&n,&m),ans = 0;
36 for (int i=1;i<=3*n;i++)
37 f[i] = i;
38 while (m--)
39 ans += cal();
40 printf("%d\n",ans);
41 }
tyvj P1460 [Tyvj March]旅行
sum表示每个集合中城市个数,cnt[i]表示加了i条边后的总和,对于每个query,二分...
感觉这个像最小生成树...
ps.才学会了输出优化...
tyvj p1460
tyvj p1700 缘如燕芳
开始以为是神题不可做,后来发现只用倒过来做就好了。
即把砍的顺序存下来,然后倒着做,即化为把a和b链接到一起。
当合并两个集合a, b的时候,假设a已经和1连到一起了,这是就要把b集合中所有的元素的时间赋为现在的时间
1 #include <cstdio>
2 #include <vector>
3 using namespace std;
4
5 const int maxn = 10000 + 10;
6 const int maxm = 100000 + 10;
7
8 vector<int> g[maxn];
9 int n, m, Clck, f[maxn], clck[maxn];
10
11 struct Edge {
12 int u, v;
13 } v[maxm], s[maxm];
14
15 int find(int x){
16 return x == f[x] ? x : f[x] = find(f[x]);
17 }
18
19 void union_set(int a, int b){
20 -- Clck;
21 int fa = find(a), fb = find(b), root = find(1);
22
23 if (fa == root && fb != root){
24 for (int i = 0, id; i < g[fb].size(); i ++){
25 id = g[fb][i];
26 clck[id] = Clck;
27 g[fa].push_back(id);
28 }
29
30 g[fb].clear();
31 f[fb] = fa;
32 }
33
34 if (fa != root && fb == root){
35 for (int i = 0, id; i < g[fa].size(); i ++){
36 id = g[fa][i];
37 clck[id] = Clck;
38 g[fb].push_back(id);
39 }
40
41 g[fa].clear();
42 f[fa] = fb;
43 }
44
45 if (fa != root && fb != root && fa != fb){
46 if (g[fa].size() > g[fb].size())
47 swap(fa, fb);
48
49 for (int i = 0; i < g[fa].size(); i ++)
50 g[fb].push_back(g[fa][i]);
51
52 g[fa].clear();
53 f[fa] = fb;
54 }
55 }
56
57 int main(){
58 scanf("%d %d", &n, &m);
59
60 Clck = m + 1;
61 for (int i = 0; i < m; i ++)
62 scanf("%d %d", &s[i].u, &s[i].v);
63
64 for (int i = 0; i < m; i ++)
65 scanf("%d %d", &s[i].u, &s[i].v);
66
67 for (int i = 1; i <= n; i ++)
68 f[i] = i, g[i].push_back(i);
69
70 for (int i = m - 1; i >= 0; i --)
71 union_set(s[i].u, s[i].v);
72
73 for (int i = 2; i <= n; i ++)
74 printf("%d\n", clck[i]);
75 }
tyvj P1863 [Poetize I]黑魔法师之门
tyvj p1863
tyvj P2044 ["扫地"杯III day2]旅游景点
仔细想一想....神奇的并查集...
1 #include <cstdio>
2 #define gc inputCh=getchar();
3 #define isDig (48<=inputCh&&inputCh<=57)
4 #define nextInt ({int _ = 0; do gc while(!isDig); do _ *= 10, _ += inputCh-48, gc while (isDig); _;})
5 using namespace std;
6
7 const int maxn = 1e5 + 10;
8
9 char inputCh;
10 int n, m, k, f[maxn];
11
12 struct Edge {
13 int u, v;
14 } e[maxn << 1];
15
16 int find(int x){
17 return x == f[x] ? x : f[x] = find(f[x]);
18 }
19
20 int main(){
21 n = nextInt, m = nextInt, k = nextInt;
22
23 for (int i = 1; i <= n; i ++)
24 f[i] = i;
25
26 int u, v, fu, fv, tot = 0;
27 for (int i = 1; i <= m; i ++){
28 u = nextInt, v = nextInt;
29
30 if (u > k && v > k){
31 fu = find(u), fv = find(v);
32 if (fu != fv)
33 f[fu] = fv;
34 }
35
36 else
37 e[tot].u = u, e[tot].v = v, tot ++;
38 }
39
40 int ans = 0;
41 for (int i = 0; i < tot; i ++){
42 fu = find(e[i].u), fv = find(e[i].v);
43 if (fu != fv)
44 f[fu] = fv;
45 else
46 ans ++;
47 }
48
49 printf("%d\n", ans);
50 }