先膜一下大佬->这里
据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解
我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举
每一行内用并查集暴力枚举连通块这个应该容易理解,就是如果是同一个同色连通块的就用并查集连起来。那么怎么处理行与行之间的连通块嘞?
因为几行连起来可以看做一块,那么我们用$[1,n]$维护最上面一行的连通性,用$[n+1,n*2]$维护最下面一行的连通性,然后用$[n*2+1,n*4]$作为辅助
这一部分的细节还是看代码好了,写在注解里了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<21],*p1=buf,*p2=buf; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 const int N=505; 20 int n,m; 21 int chess[N][N],mp[N<<2]; 22 struct node{ 23 int fa[N<<2]; 24 inline void init(){for(int i=1;i<=(n<<2);++i) fa[i]=i;} 25 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} 26 inline void unique(int x,int y){fa[find(x)]=find(y);} 27 inline bool check(int x,int y){return find(x)==find(y);} 28 }data[N<<2]; 29 int wh[N],bl[N],L[N],R[N]; 30 void pushup(int p){ 31 int mid=L[p]+R[p]>>1; 32 wh[p]=wh[p<<1]+wh[p<<1|1]; 33 bl[p]=bl[p<<1]+bl[p<<1|1]; 34 data[p].init(); 35 for(int i=1;i<=(n<<1);++i){ 36 data[p].unique(i,data[p<<1].find(i)); 37 //1~n记录左儿子最上面一行连通性 38 //n+1~n*2记录左儿子最下面一行的连通性 39 data[p].unique(i+(n<<1),data[p<<1|1].find(i)+(n<<1)); 40 //n*2+1~n*3记录右儿子最上面一行连通性 41 //n*3+1~n*4记录左儿子最下面一行的连通性 42 } 43 //枚举左右儿子交界处是否有新的连通块 44 for(int i=1;i<=n;++i) 45 if(chess[mid][i]==chess[mid+1][i]){ 46 if(data[p].check(i+n,i+(n<<1))) continue; 47 data[p].unique(i+n,i+(n<<1)); 48 wh[p]-=chess[mid][i]^1; 49 bl[p]-=chess[mid][i]; 50 } 51 //下面这一段就是把所有节点的父亲都赋值为下标最小的点 52 //顺便记录最上面一行和最下面一行的连通性 53 for(int i=1;i<=(n<<2);++i) 54 data[p].find(i),mp[i]=0; 55 for(int i=1;i<=n;++i) 56 if(!mp[data[p].fa[i]]) 57 mp[data[p].fa[i]]=i,data[p].fa[i]=i; 58 else data[p].fa[i]=mp[data[p].fa[i]]; 59 for(int i=n*3+1;i<=(n<<2);++i) 60 if(!mp[data[p].fa[i]]) 61 mp[data[p].fa[i]]=i-(n<<1),data[p].fa[i]=i-(n<<1); 62 else data[p].fa[i]=mp[data[p].fa[i]]; 63 for(int i=1;i<=n;++i) data[p].fa[i+n]=data[p].fa[i+n*3];//记录一下这一块最下面一行的连通性 64 } 65 void build(int p,int l,int r){ 66 L[p]=l,R[p]=r; 67 if(l==r){ 68 wh[p]=chess[l][1]^1; 69 bl[p]=chess[l][1]; 70 data[p].init(); 71 data[p].unique(1+n,1); 72 for(int i=2;i<=n;++i){ 73 data[p].unique(i+n,i); 74 if(chess[l][i-1]==chess[l][i]) data[p].unique(i,i-1); 75 else wh[p]+=chess[l][i]^1,bl[p]+=chess[l][i]; 76 } 77 return; 78 } 79 int mid=l+r>>1; 80 build(p<<1,l,mid),build(p<<1|1,mid+1,r); 81 pushup(p); 82 } 83 void update(int x,int p){ 84 if(L[p]==R[p]){ 85 wh[p]=chess[x][1]^1; 86 bl[p]=chess[x][1]; 87 data[p].init(); 88 data[p].unique(n+1,1); 89 for(int i=2;i<=n;++i){ 90 data[p].unique(i+n,i); 91 if(chess[x][i-1]==chess[x][i]) data[p].unique(i,i-1); 92 else wh[p]+=chess[x][i]^1,bl[p]+=chess[x][i]; 93 } 94 return; 95 } 96 int mid=L[p]+R[p]>>1; 97 if(x<=mid) update(x,p<<1); 98 else update(x,p<<1|1); 99 pushup(p); 100 } 101 int main(){ 102 //freopen("testdata.in","r",stdin); 103 n=read(); 104 for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) 105 chess[i][j]=read(); 106 build(1,1,n); 107 m=read(); 108 while(m--){ 109 int x=read(),y=read(); 110 chess[x][y]^=1; 111 update(x,1); 112 printf("%d %d ",bl[1],wh[1]); 113 } 114 return 0; 115 }