【题解】P1173 [NOI2016] 网格
dengyaotriangle · · 题解
UPD:被叉了,加了一个特判,果然这题还是需要一点特判的...
将有蛐蛐的看做黑点,有跳蚤的看做白点。
显然答案只可以是无解或者
-
若所有四联通的白色格子组成的图不连通,则答案是
0 。 -
否则若图有割点,则答案为
1 -
否则若图只有不超过两个点,则无解
-
否则为
2
前三个情况是显然的,最后一种情况可以分图有
于是直接建图跑 tarjan 即可
然而这张图点很多但是空位很少,考虑将其缩成一个点数边数均为
考虑只保留以下白点:
-
与网格四个角的至少一个角的
x,y 坐标之差\leq2 -
与某个黑点八连通
-
在网格的上边或下边上,且所在列有至少一个黑点
-
在网格的左边或右边上,且所在行有至少一个黑点
然后对于所有剩下的白点,若两个白点点在同一行或者同一列,且中间没有其它点(包括黑点黑剩下的白点),就连一条边。
注意并不是只建四连通的边。
例如这样,蓝色的格子是保留下来的点。
然后发现这张图的答案与原图的答案大多数情况是一样的,但判
我也不知道是不是对的,以及如果是对的咋证,反正过了所有 uoj hack 数据,欢迎继续hack。
而且考虑每个黑点只会最多贡献它周围
所以复杂度瓶颈在于建图,复杂度
#include<bits/stdc++.h>
using namespace std;
//dengyaotriangle!
int n,m,c;
const int maxn=2e7+10;
struct node{
int x,y,t;
node(){}
node(int x,int y,int t):x(x),y(y),t(t){}
}a[maxn];
int t,q;
bool cmp1(const node&a,const node&b){
return a.x==b.x?(a.y==b.y?a.t<b.t:a.y<b.y):a.x<b.x;
}
bool cmp2(const node&a,const node&b){
return a.y==b.y?a.x<b.x:a.y<b.y;
}
vector<int> adj[maxn];
int dfn[maxn],low[maxn],tfa[maxn],c1;
bool gt0;
void tarjan(int u){
dfn[u]=low[u]=++c1;
int cch=0;
for(int i=0;i<(int)adj[u].size();i++){
int v=adj[u][i];
if(!dfn[v]){
tfa[v]=u;
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
if(tfa[u])gt0=1;
else cch++;
}
}else if(v!=tfa[u])low[u]=min(low[u],dfn[v]);
}
if(cch>1)gt0=1;
}
void addprem(int x,int y,int radx,int rady){
for(int dx=-radx;dx<=radx;dx++){
for(int dy=-rady;dy<=rady;dy++){
int cx=x+dx,cy=y+dy;
if(1<=cx&&cx<=n&&1<=cy&&cy<=m){
a[++t]=node(cx,cy,0);
}
}
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int t_;
cin>>t_;
while(t_--){
cin>>n>>m>>c;
t=q=0;
for(int i=1;i<=c;i++){
int x,y;cin>>x>>y;
addprem(x,y,1,1);
addprem(1,y,0,0);addprem(n,y,0,0);addprem(x,1,0,0);addprem(x,m,0,0);
a[++t]=node(x,y,-1);
}
addprem(1,1,2,2);addprem(1,m,2,2);addprem(n,1,2,2);addprem(n,m,2,2);
sort(a+1,a+1+t,cmp1);
int cp=0;node buf(INT_MAX,INT_MAX,1);
for(int i=1;i<=t;i++){
if(a[i].x!=buf.x||a[i].y!=buf.y){
buf=a[i];a[++cp]=buf;
}
}
t=cp;
for(int i=1;i<=t;i++)if(a[i].t!=-1)a[i].t=++q;
for(int i=1;i<=q;i++)adj[i].clear(),dfn[i]=0;
c1=0;
for(int i=2;i<=t;i++){
if(a[i].x==a[i-1].x&&a[i].t!=-1&&a[i-1].t!=-1){
adj[a[i].t].push_back(a[i-1].t);
adj[a[i-1].t].push_back(a[i].t);
}
}
sort(a+1,a+1+t,cmp2);
for(int i=2;i<=t;i++){
if(a[i].y==a[i-1].y&&a[i].t!=-1&&a[i-1].t!=-1){
adj[a[i].t].push_back(a[i-1].t);
adj[a[i-1].t].push_back(a[i].t);
}
}
if(q<=1){
cout<< -1<<'\n';
continue;
}
if(q==2&&adj[1].size()){
int id[2];
for(int i=1;i<=t;i++)if(a[i].t>=1&&a[i].t<=2)id[a[i].t-1]=i;
if(abs(a[id[0]].x-a[id[1]].x)+abs(a[id[0]].y-a[id[1]].y)==1){
cout<< -1<<'\n';
continue;
}else{
cout<<1<<'\n';
continue;
}
}
gt0=0;
tarjan(1);
if(c1!=q){
cout<< 0<<'\n';
}else cout<<(gt0?1:2)<<'\n';
}
return 0;
}