1. POJ2236 Wireless Network
题目链接
题意:给出 n 个坏计算机的坐标,两台计算机直接通信最大距离 d,两种操作
- “O p”$(1\le p\le n)$表示修复计算机 p.
- “S p q”$(1\le p,q\le n)$表示
O 操作,判断与被修理过的所有计算机能否通信,可以合并所在集合;S 操作,判断两台计算机是否在同一集合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1005;
struct point {
int x, y;
point() {}
point(int x, int y) : x(x), y(y) {}
}p[N];
int n, d;
int fa[N], repair[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y) {
x = find(x); y = find(y);
if (x == y) return;
fa[x] = y;
}
int dis(point a, point b) {
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
int main()
{
scanf("%d%d", &n, &d);
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &p[i].x, &p[i].y);
}
char op;
int a, b, cnt = 0;
getchar();
while (~scanf("%c", &op)) {
if (op == 'O') {
scanf("%d", &a);
repair[++cnt] = a;
for (int i = 1; i < cnt; ++i) {
if (dis(p[repair[i]], p[a]) <= d * d)
unite(repair[i], a);
}
}
else {
scanf("%d%d", &a, &b);
if (find(a) == find(b)) puts("SUCCESS");
else puts("FAIL");
}
getchar();
}
return 0;
}
|
2. POJ1611 The Suspects
题目连接
题意:n 个学生$0\sim n-1$,m 个小组,0 号学生是 SARS 疑似病例,一个组有一个疑似病例则该组全部为疑似病例,求疑似病例人数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 3e4 + 5;
int n, m, k;
int fa[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y) {
x = find(x); y = find(y);
if (x == y) return;
fa[x] = y;
}
int main()
{
while (scanf("%d%d", &n, &m), n || m) {
for (int i = 0; i < n; ++i) fa[i] = i;
int x, y;
while (m--) {
scanf("%d", &k);
scanf("%d", &x);
for (int i = 2; i <= k; ++i) {
scanf("%d", &y);
unite(x, y);
}
}
int ans = 1;
int f0 = find(0);
for (int i = 1; i < n; ++i)
if (f0 == find(i)) ans++;
printf("%d\n", ans);
}
return 0;
}
|
3. HDU1213 How Many Tables
题目链接
题意:n 个人,m 组关系,关系可以传递,求共有多少组关系。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1005;
int t, n, m;
int fa[N], vis[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y) {
x = find(x); y = find(y);
if (x == y) return;
fa[x] = y;
}
int main()
{
scanf("%d", &t);
while (t--) {
memset(vis, 0, sizeof(vis));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) fa[i] = i;
int x, y;
while (m--) {
scanf("%d%d", &x, &y);
unite(x, y);
}
int ans = 0;
for (int i = 1; i <= n; ++i) vis[find(i)] = 1;
for (int i = 1; i <= n; ++i)
if (vis[i]) ans++;
printf("%d\n", ans);
}
return 0;
}
|
4. HDU3038 How Many Answers Are Wrong
题目链接
题意:在区间$[1,n]$上,给定 m 个区间和,问有几个结论矛盾。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 2e5 + 5;
int n, m, ans;
int fa[N], d[N];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
d[x] += d[fa[x]];
return fa[x] = root;
}
bool Union(int x, int y, int z) {
int fx = find(x);
int fy = find(y);
if (fx == fy) {
if (d[x] - d[y] == z) return 1;
return 0;
}
fa[fx] = fy;
d[fx] = d[y] - d[x] + z;
return 1;
}
int main()
{
while (~scanf("%d%d", &n, &m)) {
memset(d, 0, sizeof(d));
for (int i = 0; i <= n; ++i) fa[i] = i;
ans = 0;
int x, y, z;
while (m--) {
scanf("%d%d%d", &x, &y, &z);
if (!Union(x - 1, y, z)) ans++;
}
printf("%d\n", ans);
}
return 0;
}
|
5. POJ1182 食物链
题目链接
题意:$n(1\le n\le50000)$只动物,编号为$1,2,\cdots,n$,属于 A,B,C 的一种。已知 A 吃 B,B 吃 C,C 吃 A。给出以下两种信息$k(1\le k\le100000)$条。
- x 和 y 属于同一种
- x 吃 y
有一些是相互矛盾的,求不正确信息的条数。
经典老题,首先我们考虑带权并查集,两个结点有关系,即在同一棵树上find(x) == find(y)
,利用 %3 来判断捕食关系。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 5e4 + 5;
int n, k;
int fa[N], r[N];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
r[x] = (r[x] + r[fa[x]]) % 3;
return fa[x] = root;
}
bool Union(int type, int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) {
if ((r[x] - r[y] + 3) % 3 != type) return 1;
return 0;
}
fa[fx] = fy;
r[fx] = (r[y] - r[x] + type + 3) % 3;
return 0;
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) fa[i] = i;
int d, x, y;
int ans = 0;
while (k--) {
scanf("%d%d%d", &d, &x, &y);
if (x > n || y > n || (x == y && d == 2)) ans++;
else if (Union(d - 1, x, y)) ans++;
}
printf("%d\n", ans);
return 0;
}
|
考虑扩展域并查集,$1\sim n$属于 A 类,$n+1\sim 2n$属于 B 类,$2n + 1\sim 3n$属于 C 类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 5e4 + 5;
int n, k;
int fa[3 * N], r[3 * N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void Union(int x, int y) {
x = find(x); y = find(y);
if (x == y) return;
if (r[x] < r[y]) fa[x] = y;
else {
fa[y] = x;
if (r[x] == r[y]) r[x]++;
}
}
bool same(int x, int y) {
return find(x) == find(y);
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= 3 * n; ++i) fa[i] = i;
int d, x, y;
int ans = 0;
while (k--) {
scanf("%d%d%d", &d, &x, &y);
if (x > n || y > n) { ans++; continue; }
if (d == 1) {
if (same(x, y + n) || same(x, y + 2 * n)) ans++;
else {
Union(x, y);
Union(x + n, y + n);
Union(x + 2 * n, y + 2 * n);
}
}
else {
if (same(x, y) || same(x, y + 2 * n)) ans++;
else {
Union(x, y + n);
Union(x + n, y + 2 * n);
Union(x + 2 * n, y);
}
}
}
printf("%d\n", ans);
return 0;
}
|
6. POJ1417 True Liars
题目链接
题意:p 个好人,q 个坏人,n 次询问,问 x:y 是好人吗,x 是好人会说实话,否则会说谎,问能否确定所有好人。
这道题还挺难的,并查集 + dp,回答 yes 说明:x, y 都是好人或都是坏人,回答 no 说明:x, y 一个是好人另一个是坏人。
先考虑带权并查集(16 ms),d 数组为与父结点的关系,d[x]=0 表示与父结点同类,d[x]=1表示与父结点异类,dp[i][j] 表示前 i 个集合有 j 个好人的方案数,每个集合分成好人坏人两部分,w[i][0] 和 w[i][1] 表示第 i 个集合两个部分个数,dp[cnt][p] == 1 说明唯一解可行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 605;
int n, p, q, m, cnt;
int fa[N], d[N], pos[N], mp[N], vis[N];
int dp[N][N], w[N][2];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
d[x] ^= d[fa[x]];
return fa[x] = root;
}
void unite(int x, int y, int z) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return;
fa[fx] = fy;
d[fx] = d[x] ^ d[y] ^ z;
}
int main()
{
while (scanf("%d%d%d", &n, &p, &q), n || p || q) {
m = p + q;
for (int i = 1; i <= m; ++i) {
fa[i] = i, d[i] = 0;
pos[i] = 0;
mp[i] = 0;
vis[i] = -1;
}
cnt = 1;
int x, y;
char s[5];
while (n--) {
scanf("%d%d%s", &x, &y, s);
if (s[0] == 'y') unite(x, y, 0);
else unite(x, y, 1);
}
for (int i = 1; i <= m; ++i) { // 记录集合个数
x = find(i);
if (!pos[x]) {
pos[x] = cnt;
w[cnt][0] = 0;
w[cnt][1] = 0;
mp[cnt] = x;
cnt++;
}
w[pos[x]][d[i]]++;
}
cnt--;
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= cnt; ++i) {
for (int j = 0; j <= p; ++j) {
if (j - w[i][0] >= 0) {
dp[i][j] += dp[i-1][j-w[i][0]];
}
if (j - w[i][1] >= 0) {
dp[i][j] += dp[i-1][j-w[i][1]];
}
}
}
if (dp[cnt][p] == 1) {
for (int i = cnt, j = p; i > 0; --i) { // 回溯路径
if (dp[i][j] == dp[i-1][j-w[i][0]]) {
vis[i] = 0;
j -= w[i][0];
}
else if (dp[i][j] == dp[i-1][j-w[i][1]]) {
vis[i] = 1;
j -= w[i][1];
}
}
for (int i = 1; i <= m; ++i) {
if (vis[pos[fa[i]]] == d[i])
printf("%d\n", i);
}
puts("end");
}
else {
puts("no");
}
}
return 0;
}
|
再考虑扩展域并查集(79 ms),yes:unite(x, y) and unite(x + m, y + m),no:unite(x, y + n) and unite(x + n, y)。这样操作下很多集合重复,需要去重。之后 dp 即可。POJ 的 G++ 不支持 auto。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1205;
int n, p, q, m;
int fa[N], vis[N], dp[N][N], ans[N];
vector<int> v[N];
vector<int> w1[N];
vector<int> w2[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y) {
x = find(x); y = find(y);
if (x == y) return;
fa[x] = y;
}
int main()
{
while (scanf("%d%d%d", &n, &p, &q), n || p || q) {
m = p + q;
for (int i = 1; i <= 2 * m; ++i) {
fa[i] = i;
ans[i] = 0;
v[i].clear();
w1[i].clear(); w2[i].clear();
vis[i] = 0;
}
int x, y;
char s[5];
while (n--) {
scanf("%d%d%s", &x, &y, s);
if (s[0] == 'y') {
unite(x, y);
unite(x + m, y + m);
}
else {
unite(x, y + m);
unite(x + m, y);
}
}
for (int i = 1; i <= 2 * m; ++i) {
int x = find(i);
v[x].push_back(i);
}
int cnt = 1;
for (int i = 1; i <= 2 * m; ++i) {
int flag = 0;
int size = v[i].size();
for (int j = 0; j < size; ++j) {
if (v[i][j] <= m) {
if (vis[v[i][j]]) continue;
vis[v[i][j]] = 1;
flag = 1;
w1[cnt].push_back(v[i][j]);
}
else {
if (vis[v[i][j] - m]) continue;
vis[v[i][j] - m] = 1;
flag = 1;
w2[cnt].push_back(v[i][j] - m);
}
}
if (flag) cnt++;
}
cnt--;
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= cnt; ++i) {
int s1 = w1[i].size(), s2 = w2[i].size();
for (int j = p; j >= s1; --j) {
dp[i][j] += dp[i-1][j-s1];
}
for (int j = p; j >= s2; --j) {
dp[i][j] += dp[i-1][j-s2];
}
}
if (dp[cnt][p] == 1) {
for (int i = cnt, j = p; i > 0; --i) {
int s1 = w1[i].size(), s2 = w2[i].size();
if (dp[i][j] == dp[i-1][j-s1]) {
for (int k = 0; k < s1; ++k) ans[w1[i][k]] = 1;
j -= s1;
}
else if (dp[i][j] == dp[i-1][j-s2]) {
for (int k = 0; k < s2; ++k) ans[w2[i][k]] = 1;
j -= s2;
}
}
for (int i = 1; i <= m; ++i) {
if (!ans[i]) continue;
printf("%d\n", i);
}
puts("end");
}
else puts("no");
}
return 0;
}
|
7. POJ1456 Supermarket
题目链接
题意:给定 n 个商品,每个商品有利润 $p_i$ 和过期时间 $d_i$,每天只能卖出一个商品,过期商品不能再卖,问如何安排销售日期,使利润最大。
主要是贪心思想,当前最贵的商品最大限度地晚卖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1e4 + 5;
struct node {
int pri, day;
friend bool operator < (const node &a, const node &b) {
return a.pri > b.pri;
}
}p[N];
int n;
int pre[N];
int find(int x) {
if (pre[x] == -1) return x;
return pre[x] = find(pre[x]);
}
int main()
{
while (~scanf("%d", &n)) {
memset(pre, -1, sizeof(pre));
for (int i = 1; i <= n; ++i)
scanf("%d%d", &p[i].pri, &p[i].day);
sort(p + 1, p + n + 1);
int ans = 0;
for (int i = 1; i <= n; ++i) {
int time = find(p[i].day);
if (time > 0) {
ans += p[i].pri;
pre[time] = time - 1;
}
}
printf("%d\n", ans);
}
return 0;
}
|
8. POJ1733 Parity game
题目链接
题意:给出一个长度为 $n(n\le10^9)$ 的由 0 和 1 组成的序列 $S$,$m$ 个回答 $S[l\sim r]$中有奇数个 1 还是偶数个 1,输出从哪一条开始下一条错了,如果均正确输出 $m$。
n 很大,离散化处理,d[x] 为 0 表示 x 与 fa[x] 奇偶性相同,为 1 表示 x 与 fa[x] 奇偶性不同。x 和 y 不在同一集合进行合并,d[fx] = d[x] xor d[y] xor ans[i],否则进行判断。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 2e4 + 5, M = 1e4 + 5;
int n, m, cnt;
int a[N], fa[N], d[N];
int l[M], r[M], ans[M];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
d[x] ^= d[fa[x]];
return fa[x] = root;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) {
char str[5];
scanf("%d%d%s", &l[i], &r[i], str);
ans[i] = (str[0] == 'o' ? 1 : 0);
a[++cnt] = l[i] - 1;
a[++cnt] = r[i];
}
sort(a + 1, a + cnt + 1);
n = unique(a + 1, a + cnt + 1) - a - 1;
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i) {
int x = lower_bound(a + 1, a + n + 1, l[i] - 1) - a;
int y = lower_bound(a + 1, a + n + 1, r[i]) - a;
int fx = find(x), fy = find(y);
if (fx == fy) {
if ((d[x] ^ d[y]) != ans[i]) {
printf("%d\n", i - 1);
return 0;
}
}
else {
fa[fx] = fy;
d[fx] = d[x] ^ d[y] ^ ans[i];
}
}
printf("%d\n", m);
return 0;
}
|
9. POJ1984 Navigation Nightmare
题目链接
题意:n 个农场,m 条信息:F1 F2 L D 表示 F2 再农场 F1 的 D 方向的 L 距离处,k 个问题:F1 F2 I 表示知道第一到第 I 条信息情况下,求 F1 和 F2 的曼哈顿距离,无法求出输出 -1。
rx[] 记录与父结点的水平距离,ry[] 记录与父结点的垂直距离。以向东为正方向,更新时 rx[fx] = -rx[x] + ry[y] + dx[cnt],ry[fx] = -ry[x] + ry[y] + dy[cnt]。询问时,同根输出 abs(rx[x] - rx[y]) + abs(ry[x] - ry[y]),不同根无法判断关系输出 -1。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 4e4 + 5, K = 1e4 + 5;
struct query {
int x, y, index, id;
friend bool operator < (const query &a, const query &b) {
return a.index < b.index;
}
}q[K];
int n, m, l, k;
char dir;
int fa[N], rx[N], ry[N];
int u[N], v[N], dx[N], dy[N];
int ans[K];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
rx[x] += rx[fa[x]];
ry[x] += ry[fa[x]];
return fa[x] = root;
}
int main()
{
while (~scanf("%d%d", &n, &m)) {
for (int i = 1; i <= n; ++i) {
fa[i] = i;
rx[i] = ry[i] = 0;
}
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d %c", &u[i], &v[i], &l, &dir);
if (dir == 'N') { dx[i] = 0; dy[i] = l; }
else if (dir == 'E') { dx[i] = l; dy[i] = 0; }
else if (dir == 'S') { dx[i] = 0; dy[i] = -l; }
else if (dir == 'W') { dx[i] = -l; dy[i] = 0; }
}
scanf("%d", &k);
for (int i = 1; i <= k; ++i) {
scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].index);
q[i].id = i;
}
sort(q + 1, q + k + 1);
int cnt = 1;
for (int i = 1; i <= k; ++i) {
while (cnt <= q[i].index) {
int fx = find(u[cnt]);
int fy = find(v[cnt]);
fa[fx] = fy;
rx[fx] = -rx[u[cnt]] + rx[v[cnt]] + dx[cnt];
ry[fx] = -ry[u[cnt]] + ry[v[cnt]] + dy[cnt];
cnt++;
}
if (find(q[i].x) != find(q[i].y)) ans[q[i].id] = -1;
else {
ans[q[i].id] = abs(rx[q[i].x] - rx[q[i].y]) + abs(ry[q[i].x] - ry[q[i].y]);
}
}
for (int i = 1; i <= k; ++i) printf("%d\n", ans[i]);
}
return 0;
}
|
10. POJ2492 A Bug’s Life
题目链接
题意:t 组数据,每组 n 条虫,m 个关系 x y 表示 x 和 y 为异性,判断是否有矛盾。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 2005;
int t, n, m, cnt, flag;
int fa[N], d[N];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
d[x] ^= d[fa[x]];
return fa[x] = root;
}
bool Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) {
if ((d[x] ^ d[y]) == 1) return 1;
return 0;
}
fa[fx] = fy;
d[fx] = d[x] ^ d[y] ^ 1;
return 1;
}
int main()
{
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) fa[i] = i;
memset(d, 0, sizeof(d));
int x, y;
flag = 0;
while (m--) {
scanf("%d%d", &x, &y);
if (!Union(x, y)) flag = 1;
}
printf("Scenario #%d:\n", ++cnt);
if (flag) puts("Suspicious bugs found!\n");
else puts("No suspicious bugs found!\n");
}
return 0;
}
|
11. POJ2912 Rochambeau
题目链接
题意:n 个小孩进行猜拳,其中一个是裁判,剩下的小孩分成三组,同一组的小孩出同一种手势,裁判可以任意出,给出 m 次猜拳结果,问最早在第几次猜拳结果后知道裁判是谁。
枚举第 i 人为裁判,则除第 i 人外其他人判断应该无冲突,d[x] = 0:x 与 fa[x] 同类,d[x] = 1:x 吃 fa[x]:d[x] = 2,x 被 fa[x] 吃,最小的行数需要取最大值,更早的行数不能否定到只剩一人。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 505, M = 2005;
int n, m, k, flag, pos, id, cnt;
int fa[N], d[N];
int u[M], v[M];
char op[M];
int find(int x) {
if (fa[x] == x) return x;
int root = find(fa[x]);
d[x] = (d[x] + d[fa[x]]) % 3;
return fa[x] = root;
}
bool Union(int x, int y, int z) {
int fx = find(x);
int fy = find(y);
if (fx == fy) {
return (d[x] - d[y] + 3) % 3 != z;
}
fa[fx] = fy;
d[fx] = ((d[y] - d[x] + z) % 3 + 3) % 3;
return 0;
}
int main()
{
while (~scanf("%d%d", &n, &m)) {
for (int i = 1; i <= m; ++i) {
scanf("%d%c%d", &u[i], &op[i], &v[i]);
}
pos = id = cnt = 0;
for (int i = 0; i < n; ++i) {
flag = 1;
for (int j = 0; j <= n; ++j) fa[j] = j;
memset(d, 0, sizeof(d));
for (int j = 1; j <= m; ++j) {
if (u[j] == i || v[j] == i) continue;
if (op[j] == '=') k = 0;
else if (op[j] == '<') k = 1;
else if (op[j] == '>') k = 2;
if (Union(u[j], v[j], k)) {
pos = max(pos, j);
flag = 0;
break;
}
}
if (flag) {
cnt++;
id = i;
}
}
if (!cnt) puts("Impossible");
else if (cnt == 1) printf("Player %d can be determined to be the judge after %d lines\n", id, pos);
else if (cnt > 1) puts("Can not determine");
}
return 0;
}
|
12. ZOJ3261 Connections in Galaxy War
题目链接
题意:编号从 0 到 n - 1 的 n 个点,每个点有一个非负权值 $p_i$。给出 m 条边和 q 个操作,每个操作有两种形式,destroy a b:摧毁 a, b 之间的边,query a:询问从 a 出发能到达的点,点权比 a 大的最大权值点,权值最大条件下编号最小的点,若没有这样的点输出 -1。
按照题意在线去边不方便,考虑离线记录操作逆向将破坏的边添加,点权大且标号小的为祖先。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 5e4 + 5;
struct node {
char s[10];
int a, b;
}q[N];
int n, m, k, cnt;
int fa[N], p[N], u[N], v[N], ans[N];
map<int, map<int, bool> > mp;
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return;
if (p[fx] < p[fy] || (p[fx] == p[fy] && fx > fy)) fa[fx] = fy;
else fa[fy] = fx;
}
int main()
{
int flag = 0;
while (~scanf("%d", &n)) {
for (int i = 0; i <= n; ++i) fa[i] = i;
mp.clear();
for (int i = 0; i < n; ++i) scanf("%d", &p[i]);
scanf("%d", &m);
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &u[i], &v[i]);
}
scanf("%d", &k);
for (int i = 1; i <= k; ++i) {
scanf("%s", q[i].s);
if (q[i].s[0] == 'q') scanf("%d", &q[i].a);
else {
scanf("%d%d", &q[i].a, &q[i].b);
mp[q[i].a][q[i].b] = mp[q[i].b][q[i].a] = 1;
}
}
for (int i = 1; i <= m; ++i) {
if (!mp[u[i]][v[i]]) unite(u[i], v[i]);
}
cnt = 0;
for (int i = k; i >= 1; --i) {
if (q[i].s[0] == 'd') {
unite(q[i].a, q[i].b);
}
else {
int x = q[i].a;
int fx = find(x);
ans[++cnt] = p[fx] > p[x] ? fx : -1;
}
}
if (flag) puts("");
flag = 1;
for (int i = cnt; i >= 1; --i) {
printf("%d\n", ans[i]);
}
}
return 0;
}
|
13. HDU1272 小希的迷宫
题目链接
题意:无向图判环。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1e5 + 5;
int fa[N], v[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return 0;
fa[fx] = fy;
return 1;
}
int main()
{
int x, y;
while (scanf("%d%d", &x, &y), ~x || ~y) {
if (!x && !y) { puts("Yes"); continue; }
for (int i = 1; i <= N; ++i) fa[i] = i;
memset(v, 0, sizeof(v));
v[x] = v[y] = 1;
int flag = Union(x, y);
while (scanf("%d%d", &x, &y), x && y) {
if (!flag) continue;
v[x] = v[y] = 1;
if (!Union(x, y)) flag = 0;
}
if (!flag) { puts("No"); continue; }
int sum = 0; // 集合个数
for (int i = 1; i < N; ++i) {
if (v[i] && fa[i] == i) sum++;
}
if (sum > 1) puts("No");
else puts("Yes");
}
return 0;
}
|
14. POJ1308 Is It A Tree?
题目链接
题意:和上题一模一样。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 1e5 + 5;
int fa[N], v[N];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return 0;
fa[fx] = fy;
return 1;
}
int main()
{
int x, y, cnt = 0;
while (scanf("%d%d", &x, &y), ~x || ~y) {
if (!x && !y) { printf("Case %d is a tree.\n", ++cnt); continue; }
for (int i = 1; i <= N; ++i) fa[i] = i;
memset(v, 0, sizeof(v));
v[x] = v[y] = 1;
int flag = Union(x, y);
while (scanf("%d%d", &x, &y), x && y) {
if (!flag) continue;
v[x] = v[y] = 1;
if (!Union(x, y)) flag = 0;
}
if (!flag) { printf("Case %d is not a tree.\n", ++cnt); continue; }
int sum = 0;
for (int i = 1; i < N; ++i) {
if (v[i] && fa[i] == i) sum++;
}
if (sum > 1) printf("Case %d is not a tree.\n", ++cnt);
else printf("Case %d is a tree.\n", ++cnt);
}
return 0;
}
|