L i n k Link Link
J Z O J JZOJ JZOJ 3809 3809 3809
D e s c r i p t i o n Description Description
为了封印辉之环,古代塞姆利亚大陆的人民在异空间中建造了一座设备塔。
简单的说,这座设备塔是一个漂浮在异空间中的圆柱体,圆柱体两头的圆是计算核心,而侧面则是
传输信息所用的数据通道,划分成N *m 个区块。
然而,随着工作的继续进行,他们希望把侧面的一部分区块也改造成其他模块。然而,任何时候都
必须保证存在一条数据通道,能从圆柱体的一端通向另一端。
由于无法使用辉之环掌控下的计算系统,他们寻求你的帮助来解决这个问题。他们将逐个输入想要
改造的区域,而你则执行所有可行的改造并忽略可能导致数据中断的改造。
I n p u t Input Input
第一行,包含两个整数N;M;K,表示侧面的长和宽,以及操作数。
接下来K 行,每行包含三个整数xi; yi,表示操作的区块的坐标。(0<=y=<M)
数据保证不会对已经操作成功的区块进行操作.
O u t p u t Output Output
输出一行,表示有多少个操作可以被执行。
S a m p l e Sample Sample I n p u t Input Input
3 4 9
2 2
3 2
2 3
3 4
3 1
1 3
2 1
1 1
1 4
S a m p l e Sample Sample O u t p u t Output Output
6
H i n t Hint Hint
• 对于分值为30 的子任务1,保证N;M <=100;K<= 5000
• 对于分值为30 的子任务2,保证N;M <=3000;K <= 5000
• 对于分值为40 的子任务3,保证N;M <=3000;K <= 300000。
黄色点表示可加的点,红色点表示不可加的点
T r a i n Train Train o f of of T h o u g h t Thought Thought
因为是圆柱体,把原图倍长一倍,每次加一个点,就在它这个图的复制图的对应点也标记上,判断这两个点是否联通,联通则不可加,否则就可以加
判断是否联通可以用并查集
但是!
∵ 如果你当前在
(
x
,
(x,
(x,
1
)
1)
1),然后往左跳, 变为
(
x
,
(x,
(x,
0
)
0)
0),而
(
x
,
(x,
(x,
0
)
0)
0)其实等于
(
x
,
(x,
(x,
2
∗
m
)
2 * m)
2∗m)
∴ 需要这一类操作:
C o d e Code Code
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n, m, x, y, tot, t, ans;
int a[3005][6005], fa[2000005];
int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
int dy[8] = {1, 1, 0, -1, -1, -1, 0, 1};
int find(int x)
{
if (fa[x] == x) return x;
else return fa[x] = find(fa[x]);
}//寻找祖先
bool check(int x, int y)
{
int x2 = x, y2 = y + m;
for (int i = 0; i < 8; ++i)
{
int xa = x + dx[i], ya = y + dy[i];
if (ya < 1) ya = 2 * m;
if (ya > 2 * m) ya = 1;
if (xa < 1 || xa > n || !a[xa][ya]) continue;
for (int j = 0; j < 8; ++j)
{
int xb = x2 + dx[j], yb = y2 + dy[j];
if (yb > 2 * m) yb = 1;
if (yb < 1) yb = 2 * m;
if (xb < 1 || xb > n || !a[xb][yb]) continue;
if (a[xa][ya] && a[xb][yb] && find(a[xa][ya]) == find(a[xb][yb])) //判断是否联通
return 0;
}
}
return 1;
}
void unicom(int ax, int bx)
{
int Fa = find(ax), Fb = find(bx);
if (Fa == Fb) return;
if (Fa > Fb) fa[Fa] = Fb;
else fa[Fb] = Fa;
}//联通祖先
void findfa(int tx, int ty)
{
a[tx][ty] = ++tot;
fa[tot] = tot;
for (int i = 0; i < 8; ++i)
{
int txa = tx + dx[i], tya = ty + dy[i];
if (tya < 1) tya = 2 * m;
if (tya > 2 * m) tya = 1;
if (txa < 1 || txa > n || !a[txa][tya]) continue;
unicom(tot, a[txa][tya]);
}
}
int main()
{
scanf("%d%d%d", &n, &m, &t);
for (int i = 1; i <= t; ++i)
{
scanf("%d%d", &x, &y);
if (check(x, y)) {//是否联通
ans++;
findfa(x, y); findfa(x, y + m);//刷新它邻点的祖先(并且帮当前点找到祖先)
}
}
printf("%d", ans);
}