任意两点之间有且只有一条简单路径
⇔
树
所以就是要使剩下的点构成一颗树,容易发现,随着格子数变多,边数增长的比点数快,且
K
不会很大。所以当
然后就是暴力判断了。直接并查集。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500005;
typedef long long LL;
int _test,n,m,K,fa[maxn],tot_e;
bool vis[maxn];
int ID(int x,int y){ return (x-1)*m+y; }
int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }
bool Add(int x,int y){
if(vis[x]||vis[y]) return true;
if(getfa(x)==getfa(y)) return false;
tot_e++;
return fa[getfa(x)]=getfa(y),true;
}
bool check(){
tot_e=0;
for(int i=1;i<=n*m;i++) fa[i]=i;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j<m){
if(!Add(ID(i,j),ID(i,j+1))) return false;
} else{
if(!Add(ID(i,j),ID(i,1))) return false;
}
if(i<n) if(!Add(ID(i,j),ID(i+1,j))) return false;
}
}
int t=0; for(int i=1;i<=n*m;i++) if(!vis[i]) t=getfa(i);
for(int i=1;i<=n*m;i++) if(!vis[i]&&getfa(i)!=t) return false;
return true;
}
int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d",&_test);
while(_test--){
memset(vis,0,sizeof(vis));
scanf("%d%d%d",&n,&m,&K);
if((LL)n*m>500000){ printf("No\n"); for(int i=1;i<=K;i++) scanf("%*d%*d"); continue; }
for(int i=1;i<=K;i++){
int x,y; scanf("%d%d",&x,&y);
vis[ID(x,y)]=true;
}
if(check()) printf("Yes\n"); else printf("No\n");
}
return 0;
}