思路:
蛋疼的一道题
当时做同步赛的时候这道题爆零了= =
%%%TA爷现场AC
连c=0的情况也没写
用到的算法很简单,离散化+求割点(然而当时的我并不会求割点= =)
但是写起来有很多要注意的细节问题
先说一下总体做法
很容易想到答案就是-1,0,1,2(显然,当时的我就算没学割点也看出来了……)
考虑分开讨论
-1
n∗m−k<=1
或(
n∗m−k=2
且连在一起)
0
n∗m−k>=2
且至少存在两个联通块
1
只有一个联通块,但有割点
2
除上面三种情况以外
情况看起来也很简单啊
但是实现起来并不容易
因为
n
,
怎么建呢?
所有蛐蛐周围一圈的八个点
一开始我想的是建周围两圈,即24个点
然后检查每个跳蚤往其向下和向右碰到的第一个点,如果也是跳蚤就连边(这个可以分别按照x,y的关键字优先级排序来做)
然后dfs一遍,检查是否连通及是否存在割点即可
但如果仅仅这样建图,下面这个样例是无法处理的
5 5 1
3 5
画出来是这样的
如果如上建图,
5×5
的网格就变成了
3×3
的网格,原本不存在割点,而现在又有了
那怎么办呢?
我们可以把这个图再扩大一圈
也就是说检查我们所离散的点是否已经到达网格的边界,如果没有到达,就在他们周围在加一圈
比如上述这个样例错误的离散化是这样的
(因为这样就出来割点了)
正确的离散化
(实际上就是把最小的x,y-1,最大的x,y+1,注意不能超过[1,n],[1,m]的范围)
这样建好图以后就可以跑tarjan求割点了
注意数组范围的大小
每个蝈蝈最多可以扩展出8个点,而且离散后的x,y坐标为
1
~
这样总点数大约是
2×106
个
每个点最多会向外连4条边,所以边数为
8×106
在UOJ上刷了一页的97pts
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define M 100005
#define LL long long
using namespace std;
int T,n,m,k,ID,cnt,tot,lef,rit,up,down;
bool any_cut,key;
struct node{
int id,x,y;
bool operator <(const node other)const
{
if (key)
if (x==other.x) return y<other.y;
else return x<other.x;
else
if (y==other.y) return x<other.x;
else return y<other.y;
}
bool operator ==(const node other)const
{
return x==other.x&&y==other.y;
}
}a[M],b[M*25];
int X[M*3],Y[M*3],first[M*25],low[M*25],dfn[M*25];
struct edge{
int v,next;
}e[M*90];
int in()
{
int t=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
void add(int x,int y)
{
e[++tot].v=y;e[tot].next=first[x];first[x]=tot;
e[++tot].v=x;e[tot].next=first[y];first[y]=tot;
}
void dfs(int x,int fa)
{
dfn[x]=low[x]=++dfn[0];
int child=0;
for (int i=first[x];i;i=e[i].next)
if (e[i].v!=fa)
if (!dfn[e[i].v])
{
child++;
dfs(e[i].v,x);
low[x]=min(low[x],low[e[i].v]);
if (fa&&dfn[x]<=low[e[i].v])
any_cut=1;
if (!fa&&child>=2)
any_cut=1;
}
else
low[x]=min(low[x],dfn[e[i].v]);
}
void work()
{
n=in();m=in();k=in();
X[0]=0;Y[0]=0;cnt=0;ID=0;tot=0;any_cut=0;
e[1].v=0;
for (int x,y,i=1;i<=k;++i)
{
x=in();y=in();
a[i]=(node){0,x,y};
if (x>1) X[++X[0]]=x-1,b[++ID]=(node){0,x-1,y};
if (x<n) X[++X[0]]=x+1,b[++ID]=(node){0,x+1,y};
X[++X[0]]=x;
if (y>1) Y[++Y[0]]=y-1,b[++ID]=(node){0,x,y-1};
if (y<m) Y[++Y[0]]=y+1,b[++ID]=(node){0,x,y+1};
Y[++Y[0]]=y;
if (x>1&&y>1) b[++ID]=(node){0,x-1,y-1};
if (x>1&&y<m) b[++ID]=(node){0,x-1,y+1};
if (x<n&&y>1) b[++ID]=(node){0,x+1,y-1};
if (x<n&&y<m) b[++ID]=(node){0,x+1,y+1};
}
if ((LL)n*m-k<=1) return void(puts("-1"));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(first,0,sizeof(first));
up=lef=M,down=rit=0;
for (int i=1;i<=X[0];++i)
lef=min(X[i],lef),
rit=max(X[i],rit);
for (int i=1;i<=Y[0];++i)
up=min(Y[i],up),
down=max(Y[i],down);
if (lef>1) --lef;
if (rit<n) ++rit;
if (up>1) --up;
if (down<m) ++down;
X[++X[0]]=lef;X[++X[0]]=rit;
Y[++Y[0]]=up;Y[++Y[0]]=down;
sort(X+1,X+X[0]+1);
X[0]=unique(X+1,X+X[0]+1)-X-1;
sort(Y+1,Y+Y[0]+1);
Y[0]=unique(Y+1,Y+Y[0]+1)-Y-1;
for (int i=1;i<=X[0];++i)
b[++ID]=(node){0,X[i],Y[1]},
b[++ID]=(node){0,X[i],Y[Y[0]]};
for (int i=1;i<=Y[0];++i)
b[++ID]=(node){0,X[1],Y[i]},
b[++ID]=(node){0,X[X[0]],Y[i]};
key=0;
sort(a+1,a+k+1);
sort(b+1,b+ID+1);
ID=unique(b+1,b+ID+1)-b-1;
for (int i=1;i<=k;++i)
a[i].x=lower_bound(X+1,X+X[0]+1,a[i].x)-X,
a[i].y=lower_bound(Y+1,Y+Y[0]+1,a[i].y)-Y;
for (int i=1;i<=ID;++i)
b[i].x=lower_bound(X+1,X+X[0]+1,b[i].x)-X,
b[i].y=lower_bound(Y+1,Y+Y[0]+1,b[i].y)-Y,
b[i].id=i;
for (int t=1,tt=1,i=1;i<=ID;++i)
{
node tmp=b[i];
while (t<=k&&a[t]<tmp) ++t;
if (t>=1&&t<=k&&a[t]==tmp) continue;
++cnt;
tmp.x++;
while (t<=k&&a[t]<tmp) ++t;
while (tt<=ID&&b[tt]<tmp) ++tt;
if (tt>=1&&tt<=ID&&b[tt].y==b[i].y&&b[tt].x>b[i].x&&(t<1||t>k||b[tt]<a[t]))
add(b[i].id,b[tt].id);
}
key=1;
sort(a+1,a+k+1);
sort(b+1,b+ID+1);
for (int t=1,tt=1,i=1;i<=ID;++i)
{
node tmp=b[i];
while (t<=k&&a[t]<tmp) ++t;
if (t>=1&&t<=k&&a[t]==tmp) continue;
tmp.y++;
while (t<=k&&a[t]<tmp) ++t;
while (tt<=ID&&b[tt]<tmp) ++tt;
if (tt>=1&&tt<=ID&&b[tt].x==b[i].x&&b[tt].y>b[i].y&&(t<1||t>k||b[tt]<a[t]))
add(b[i].id,b[tt].id);
}
if (e[1].v) dfs(e[1].v,0);
if ((LL)n*m-k==2&&(dfn[0]==2||!k)) return void(puts("-1"));
if ((LL)n*m-k>=2&&dfn[0]<cnt) return void(puts("0"));
if (dfn[0]==cnt&&any_cut) return void(puts("1"));
if (n==1||m==1) return void(puts("1"));
puts("2");
}
main()
{
for (T=in();T;--T) work();
}