分析:这是一个连通性的问题。你会发现如果将所有操作逆序来看的话就很容易用并查集来处理了。 首先把所有的山峰都加到图中,然后逆序处理每个操作:
对某次操作,在图中删除该位置的山峰,然后判断两个点是否联通,一旦联通就得到了结果。 这里需要对China和India分别新建一个对应的节点。
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long LL; const int N=1e3+5; const int INF=0x3f3f3f3f; char s[N][N]; struct Que { int x,y; } p[N*N]; int dx[4]= {0,0,-1,1}; int dy[4]= {-1,1,0,0}; int fa[N*N],r[N*N]; int find(int x) { if(x==fa[x])return x; return fa[x]=find(fa[x]); } void fun(int x,int y) { x=find(x),y=find(y); if(x!=y) { if(r[x]>r[y]) { fa[y]=x; } else if(r[x]<r[y]) { fa[x]=y; } else fa[y]=x,++r[x]; } } int main() { int T; scanf("%d",&T); while(T--) { int n,m,q; scanf("%d%d",&n,&m); for(int i=1; i<=n; ++i) scanf("%s",s[i]+1); scanf("%d",&q); for(int i=1; i<=q; ++i) { scanf("%d%d",&p[i].x,&p[i].y); ++p[i].x,++p[i].y; s[p[i].x][p[i].y]='1'; } for(int i=1; i<=n*m+2; ++i)fa[i]=i,r[i]=0; int k1=n*m+1,k2=n*m+2; for(int i=1; i<=m; ++i) { if(s[1][i]=='0')fun(k1,i); if(s[n][i]=='0')fun(k2,(n-1)*m+i); } for(int i=1; i<=n; ++i) { for(int j=1; j<=m; ++j) { if(s[i][j]=='1')continue; if(i<n&&s[i+1][j]=='0')fun((i-1)*m+j,i*m+j); if(j<m&&s[i][j+1]=='0')fun((i-1)*m+j,(i-1)*m+j+1); } } if(find(k1)==find(k2)) { printf("-1 "); continue; } int ans=0; for(int i=q; i>0; --i) { int x=p[i].x,y=p[i].y; s[x][y]='0'; if(x==1)fun(k1,y); if(x==n)fun(k2,(n-1)*m+y); for(int j=0; j<4; ++j) { int xx=x+dx[j]; int yy=y+dy[j]; if(xx<1||xx>n||yy<1||yy>m)continue; if(s[xx][yy]=='1')continue; fun((x-1)*m+y,(xx-1)*m+yy); } if(find(k1)==find(k2)) { ans=i; break; } } printf("%d ",ans); } return 0; }