题意:给你一个棋盘,棋盘格子有颜色,每次都会单点修改,问你修改后的白色和黑色联通块的数量。
题解:并查集是可以用来求联通块数量的,如果没有修改就是一个简单的带权并查集,但是由于有修改并且在棋盘上,所以如果只是并查集是不足以完成的,然后注意题目限制1 ≤ n≤ 200,而且每次只是单点修改,修改直接影响的只有当前列(将棋盘按列分割开)对于其他列是没有影响的,然后就只会在相邻行合并时产生影响,通过线段树按行建树后,修改操作只会影响logm层,所以每次对于修改直接暴力维护并查集,时间复杂度为nlogm,由于n很小,复杂度完全能够接受,对于答案只需要O(1)输出根节点储存的信息
AC代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
char c;int x=0,y=1;while(c=getchar(),(c<'0'||c>'9')&&c!='-');
if(c=='-') y=-1;else x=c-'0';while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';return x*y;
}
const int maxn=2e2+5;
struct node{
int L[maxn],R[maxn];
int ans[2];
}tree[maxn*4];
int fa[maxn*maxn],mp[maxn][maxn],n;
inline int getid(int x,int y){
return (x-1)*n+y;
}
inline int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
inline void pushup(node &ci,node ai,node bi,int m){
for(int a=1;a<=n;a++){
ci.L[a]=ai.L[a];
ci.R[a]=bi.R[a];
fa[ai.L[a]]=ai.L[a];
fa[ai.R[a]]=ai.R[a];
fa[bi.L[a]]=bi.L[a];
fa[bi.R[a]]=bi.R[a];
}
ci.ans[0]=ai.ans[0]+bi.ans[0];
ci.ans[1]=ai.ans[1]+bi.ans[1];
for(int a=1;a<=n;a++){
if(mp[a][m]==mp[a][m+1]){
int fi=find(ai.R[a]),fj=find(bi.L[a]);
if(fi!=fj){
fa[fi]=fj;
ci.ans[mp[a][m]]--;
}
}
}
for(int a=1;a<=n;a++){
ci.L[a]=find(ci.L[a]);
ci.R[a]=find(ci.R[a]);
}
}
inline void build(int l,int r,int k){
if(l==r){
tree[k].ans[0]=tree[k].ans[1]=0;
for(int a=1;a<=n;a++)
tree[k].L[a] = tree[k].R[a] = getid(a, l),tree[k].ans[mp[a][l]]++;
for(int a=2;a<=n;a++)
if(mp[a][l]==mp[a-1][l])
tree[k].L[a]=tree[k].R[a]=tree[k].L[a-1],tree[k].ans[mp[a][l]]--;
return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
pushup(tree[k],tree[k<<1],tree[k<<1|1],mid);
}
inline void modify(int l,int r,int k,int l1){
if(l==r){
tree[k].ans[0]=tree[k].ans[1]=0;
for(int a=1;a<=n;a++)
tree[k].L[a] = tree[k].R[a] = getid(a, l),tree[k].ans[mp[a][l]]++;
for(int a=2;a<=n;a++)
if(mp[a][l]==mp[a-1][l])
tree[k].L[a]=tree[k].R[a]=tree[k].L[a-1],tree[k].ans[mp[a][l]]--;
return ;
}
int mid=(l+r)>>1;
if(mid>=l1) modify(l,mid,k<<1,l1);
else modify(mid+1,r,k<<1|1,l1);
pushup(tree[k],tree[k<<1],tree[k<<1|1],mid);
}
int main( ){
n=read();
for(int a=1;a<=n;a++) for(int b=1;b<=n;b++) mp[a][b]=read();
build(1,n,1);
int q=read();
while(q--){
int x=read(),y=read();
mp[x][y]^=1;
modify(1,n,1,y);
printf("%d %d\n",tree[1].ans[1],tree[1].ans[0]);
}
}