正题
题目链接:https://jzoj.net/senior/#contest/show/2955/2
题目大意
n∗mn*mn∗m的矩阵,最左边和最右边是联通的,然后每次加入一个墙求能否有一条路径从最上方到最下方。如果有就加入否则不加入。
求最后有多少个墙。
解题思路
我们对于每个墙往八个方向的墙连边,我们发现在同一个联通块里的墙你是无法穿过的。
我们先复制一份矩阵放在左边,然后我们发现若有一个块和复制后对应位置的块是联通的那么就不可行(因为复制一份所以Wall−>Wall′Wall->Wall'Wall−>Wall′和Wall′−>WallWall'->WallWall′−>Wall都是不可以穿过的)。
用并查集判断即可。
codecodecode
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=3100,dx[8]={0,0,1,-1,1,-1,1,-1},dy[8]={1,-1,0,0,-1,1,1,-1};
int n,m,c[N][2*N],fa[3100000],cnt,ans,T;
int read() {int x=0,f=1; char c=getchar();while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();return x*f;
}
int find(int x)
{return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
void unionn(int x,int y)
{int Fa=find(x),Fb=find(y);if(Fa==Fb) return;if(Fa<Fb) fa[Fb]=Fa;else fa[Fa]=Fb;
}
bool check(int x1,int y1)
{int x2=x1,y2=y1+m;for(int i=0;i<8;i++){int zx=x1+dx[i],zy=y1+dy[i];if(zx<1||zx>n||!c[zx][zy]) continue;if(zy<1) zy=2*m;if(zy>2*m) zy=1;for(int j=0;j<8;j++){int sx=x2+dx[j],sy=y2+dy[j];if(sx<1||sx>n||!c[sx][sy]) continue;if(sy<1) sy=2*m;if(sy>2*m) sy=1;if(c[zx][zy]&&c[sx][sy]&&find(c[zx][zy])==find(c[sx][sy]))return 0;}}return 1;
}
void act3(int x,int y)
{c[x][y]=++cnt;fa[cnt]=cnt;for(int k=0;k<8;k++){int zx=x+dx[k],zy=y+dy[k];if(zy<1) zy=2*m;if(zy>2*m) zy=1;if(zx<1||zx>n||!c[zx][zy]) continue;unionn(c[x][y],c[zx][zy]);}
}
int main()
{n=read();m=read();T=read();while(T--){int x=read(),y=read();// if(c[x][y]) continue;if(check(x,y))ans++,act3(x,y),act3(x,y+m);}if(m==1) printf("0");else printf("%d",ans);
}