BZOJ_4423_[AMPPZ2013]Bytehattan_对偶图+并查集

BZOJ_4423_[AMPPZ2013]Bytehattan_对偶图+并查集

Description

比特哈顿镇有n*n个格点,形成了一个网格图。一开始整张图是完整的。
有k次操作,每次会删掉图中的一条边(u,v),你需要回答在删除这条边之后u和v是否仍然连通。

Input

第一行包含两个正整数n,k(2<=n<=1500,1<=k<=2n(n-1)),表示网格图的大小以及操作的个数。
接下来k行,每行包含两条信息,每条信息包含两个正整数a,b(1<=a,b<=n)以及一个字符c(c=N或者E)。
如果c=N,表示删除(a,b)到(a,b+1)这条边;如果c=E,表示删除(a,b)到(a+1,b)这条边。
数据进行了加密,对于每个操作,如果上一个询问回答为TAK或者这是第一个操作,那么只考虑第一条信息,否则只考虑第二条信息。
数据保证每条边最多被删除一次。

Output

输出k行,对于每个询问,如果仍然连通,输出TAK,否则输出NIE。

Sample Input

3 4
2 1 E 1 2 N
2 1 N 1 1 N
3 1 N 2 1 N
2 2 N 1 1 N

Sample Output

TAK
TAK
NIE
NIE

由于是网格图所以想到平面图和对偶图之间的转化。
那对于这道题,可以发现这样一个规律:
把每个点i当做是以它为左上角的方块中的点i'。
那么u,v之间的割掉的边可以用u',v'之间连接的一些边替代。
也就是每一个可能的平面图,都对应着一个对偶图,在这个对偶图上,连通表示割。
然后并查集维护一下连通性即可。
BB这么多代码还是很简单的。
 
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N (1550*1550)
int fa[N],n,m,idx[1550][1550];
char s[10];
int find(int x) {
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main() {
    scanf("%d%d",&n,&m);n--;
    int i,j,ans=0,x,y,a,b;
    for(i=1;i<=n;i++) idx[0][i]=idx[i][n+1]=idx[i][0]=idx[n+1][i]=0;
    for(i=1;i<=n;i++) for(j=1;j<=n;j++) idx[i][j]=(i-1)*n+j;
    for(i=0;i<=n*n;i++) fa[i]=i;
    while(m--) {
        if(ans) scanf("%*d%*d%*s%d%d%s",&a,&b,s);
        else scanf("%d%d%s%*d%*d%*s",&a,&b,s);
        x=(s[0]=='N')?idx[a-1][b]:idx[a][b-1];
        y=idx[a][b];
        int dx=find(x),dy=find(y);
        if(dx!=dy) puts("TAK"),ans=0;
        else puts("NIE"),ans=1;
        fa[dx]=dy;
    }
}
原文地址:https://www.cnblogs.com/suika/p/9203823.html