跳蚤国王和蛐蛐国王在玩一个游戏。
他们在一个 n n 行 m m 列的网格上排兵布阵。其中的 c c 个格子中 (0≤c≤nm) ( 0 ≤ c ≤ n m ) ,每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。
我们称占据的格子有公共边的两只跳蚤是相邻的。
我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻,或存在另一只跳蚤与这两只跳蚤都连通。
现在,蛐蛐国王希望,将某些(零个,一个或多个)跳蚤替换成蛐蛐,使得在此之后存在至少两只跳蚤不连通。
例如:我们用图表示一只跳蚤,用图表示一只蛐蛐,那么左图描述了一个 n=4, m=4, c=2 n = 4 , m = 4 , c = 2 的情况。
这种情况下蛐蛐国王可以通过将第二行第二列,和第三行第三列的两只跳蚤替换为蛐蛐,从而达成他的希望,如右图所示。并且,不存在更优的方案,但是可能存在其他替换两只跳蚤的方案。
你需要首先判断蛐蛐国王的希望能否被达成。如果能够达成,你还需要最小化被替换的跳蚤的个数。
每个输入文件包含多组数据。
输入文件的第一行只有一个整数 T T ,表示数据的组数。
接下来依次输入 T T 组数据,每组数据的第一行包含三个整数 n,m,c n , m , c 。
接下来 c c 行,每行包含两个整数 x,y x , y 表示第 x x 行,第 y y 列的格子被一个蛐蛐占据。每一组数据当中,同一个蛐蛐不会被多次描述。
同一行相邻的整数之间由一个空格隔开。
对于每一组数据依次输出一行答案。
如果这组数据中,蛐蛐国王的希望不能被达成,输出-1
。否则,输出被替换的跳蚤的个数的最小值。
4
4 4 2
1 1
4 4
2 3 1
1 2
2 2 2
1 1
2 2
1 1 0
2
1
0
-1
第一组数据就是问题描述中的例子。
对于第二组数据,可以将第二行第二列的一只跳蚤替换为蛐蛐,从而使得存在两只跳蚤不连通,并且不存在更优的方案。
对于第三组数据,最初已经存在两只跳蚤不连通,故不需要再进行替换。
对于第四组数据,由于最多只有一只跳蚤,所以无论如何替换都不能存在两只跳蚤不连通。
对于所有的数据, 1≤n,m≤109, 0≤c≤min(nm,105), 1≤x≤n, 1≤y≤m, 1≤T≤20 1 ≤ n , m ≤ 10 9 , 0 ≤ c ≤ min ( n m , 10 5 ) , 1 ≤ x ≤ n , 1 ≤ y ≤ m , 1 ≤ T ≤ 20 。
我们记 ∑c ∑ c 为某个测试点中,其 T T 组输入数据的所有 c c 的总和,则保证 ∑c≤105 ∑ c ≤ 10 5 。
首先答案不会超过 2 2 ,因为至少有一个跳蚤所在的格子相邻的跳蚤不超过 2 2 个。
对于答案是 −1 − 1 的情况,有两种情况:
1. 只有一只跳蚤。
2. 只有两只跳蚤,并且他们相邻。
图不连通的时候答案为 0 0 。 图有割点的情况答案为 1 1 (把割点便乘蛐蛐)。其他的情况答案就是 2 2 。
然后转化成了一张网格图让你求割点。
考虑到蛐蛐数量很少,连续 >2 > 2 行跳蚤与 2 2 行跳蚤是等价的,所以可以直接离散化,于是就能得到 84 84 分了。
但是蛐蛐有 105 10 5 次方级别,很显然不能直接离散化。
std 的思路非常妙,就是只保留每个蛐蛐周围 5×5 5 × 5 共 25 25 个格子,中间空出来的直接连边。于是点数是 2.5×106 2.5 × 10 6 级别的,可以通过,复杂度 O(c) O ( c ) 。
#include
using namespace std;
int dd;
struct node{
int id, x, y;
node(){}
node(int _x, int _y){
id = 0; x = _x; y = _y;
}
node(int _id, int _x, int _y){
id = _id; x = _x; y = _y;
}
bool operator < (const node &b) const{
if(dd == 0){
if(x == b.x) return y < b.y;
return x < b.x;
}else{
if(y == b.y) return x < b.x;
return y < b.y;
}
}
bool operator <= (const node &b) const{
if(dd == 0){
if(x == b.x) return y <= b.y;
return x < b.x;
}else{
if(y == b.y) return x <= b.x;
return y < b.y;
}
}
bool operator == (const node &b) const{
return x == b.x && y == b.y;
}
}a[100005], b[10000005];
int n, m, c, k;
int ax[300005], ay[300005], cx, cy;
struct edge{
int to, nxt;
}e[10000005];
int h[2500005], cnt;
void addedge(int x, int y){
cnt++; e[cnt].to = y; e[cnt].nxt = h[x]; h[x] = cnt;
cnt++; e[cnt].to = x; e[cnt].nxt = h[y]; h[y] = cnt;
}
int dfn[2500005], low[2500005], cut;
void dfs(int x, int fa){
dfn[x] = low[x] = ++dfn[0];
int cc = 0;
for(int i = h[x]; i; i = e[i].nxt){
if(e[i].to == fa) continue;
if(!dfn[e[i].to]){
cc++; dfs(e[i].to, x);
low[x] = min(low[x], low[e[i].to]);
if(fa && dfn[x] <= low[e[i].to]) cut = 1;
if(!fa && cc >= 2) cut = 1;
}else low[x] = min(low[x], dfn[e[i].to]);
}
}
void pre(){
for(int i = 0; i <= k; i ++){
h[i] = dfn[i] = low[i] = 0;
}
cnt = cut = 0;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &m, &c); k = cx = cy = 0;
if(c == 0){
if(1ll * n * m <= 2) puts("-1");
else if(n == 1 || m == 1) puts("1");
else puts("2");
continue;
}
for(int i = 1; i <= c; i ++){
int x, y;
scanf("%d%d", &x, &y);
a[i].x = x; a[i].y = y;
ax[++cx] = x; ay[++cy] = y;
if(x > 1) ax[++cx] = x - 1, b[++k] = node(x - 1, y);
if(x < n) ax[++cx] = x + 1, b[++k] = node(x + 1, y);
if(y > 1) ay[++cy] = y - 1, b[++k] = node(x, y - 1);
if(y < m) ay[++cy] = y + 1, b[++k] = node(x, y + 1);
if(x > 1 && y > 1) b[++k] = node(x - 1, y - 1);
if(x > 1 && y < m) b[++k] = node(x - 1, y + 1);
if(x < n && y > 1) b[++k] = node(x + 1, y - 1);
if(x < n && y < m) b[++k] = node(x + 1, y + 1);
}
if(1ll * n * m - c < 2){
puts("-1"); continue;
}
int mnx = n, mny = m, mxx = 1, mxy = 1;
for(int i = 1; i <= cx; i ++){
mnx = min(mnx, ax[i]);
mxx = max(mxx, ax[i]);
}
for(int i = 1; i <= cy; i ++){
mny = min(mny, ay[i]);
mxy = max(mxy, ay[i]);
}
if(mnx > 1) mnx--; if(mxx < n) mxx++;
if(mny > 1) mny--; if(mxy < m) mxy++;
ax[++cx] = mnx; ax[++cx] = mxx;
ay[++cy] = mny; ay[++cy] = mxy;
sort(ax + 1, ax + cx + 1); cx = unique(ax + 1, ax + cx + 1) - ax - 1;
sort(ay + 1, ay + cy + 1); cy = unique(ay + 1, ay + cy + 1) - ay - 1;
for(int i = 1; i <= cx; i ++){
b[++k] = node(ax[i], ay[1]);
b[++k] = node(ax[i], ay[cy]);
}
for(int i = 1; i <= cy; i ++){
b[++k] = node(ax[1], ay[i]);
b[++k] = node(ax[cx], ay[i]);
}
sort(a + 1, a + c + 1);
sort(b + 1, b + k + 1); k = unique(b + 1, b + k + 1) - b - 1;
for(int i = 1; i <= c; i ++){
a[i].x = lower_bound(ax + 1, ax + cx + 1, a[i].x) - ax;
a[i].y = lower_bound(ay + 1, ay + cy + 1, a[i].y) - ay;
}
for(int i = 1; i <= k; i ++){
b[i].x = lower_bound(ax + 1, ax + cx + 1, b[i].x) - ax;
b[i].y = lower_bound(ay + 1, ay + cy + 1, b[i].y) - ay;
b[i].id = i;
}
pre();
dd = 1; sort(a + 1, a + c + 1); sort(b + 1, b + k + 1);
int cc = 0;
for(int i = 1, t1 = 1, t2 = 1; i <= k; i ++){
while(t1 <= c && a[t1] < b[i]) t1++;
if(a[t1] == b[i] && t1 <= c) continue;
cc++;
while(t1 <= c && a[t1] <= b[i]) t1++;
while(t2 <= k && b[t2] <= b[i]) t2++;
if(t2 <= k && b[t2].y == b[i].y && b[t2].x > b[i].x && (t1 > c || !(b[t2] == a[t1]))) addedge(b[i].id, b[t2].id);
}
dd = 0; sort(a + 1, a + c + 1); sort(b + 1, b + k + 1);
for(int i = 1, t1 = 1, t2 = 1; i <= k; i ++){
while(t1 <= c && a[t1] < b[i]) t1++;
if(a[t1] == b[i] && t1 <= c) continue;
while(t1 <= c && a[t1] <= b[i]) t1++;
while(t2 <= k && b[t2] <= b[i]) t2++;
if(t2 <= k && b[t2].x == b[i].x && b[t2].y > b[i].y && (t1 > c || !(b[t2] == a[t1]))) addedge(b[i].id, b[t2].id);
}
if(cnt) dfs(e[1].to, 0);
if(1ll * n * m - c == 2 && dfn[0] == 2) puts("-1");
else if(dfn[0] < cc) puts("0");
else if(cut || dfn[0] == 2) puts("1");
else puts("2");
}
return 0;
}