[WC2005]双面棋盘(线段树+并查集)

线段树+并查集维护连通性。

好像 (700ms) 的时限把我的常数超级大的做法卡掉了, 必须要开 (O_2) 才行。

对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并。

(Code Below:)

#include <bits/stdc++.h>
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
const int maxn=200+10;
int n,m,a[maxn][maxn],f[maxn<<2],tmp[maxn<<2],wsum[maxn<<2],bsum[maxn<<2],lfa[maxn<<2][maxn],rfa[maxn<<2][maxn];

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}

int find(int x,int *f){
	return (x==f[x])?x:f[x]=find(f[x],f);
}

inline void pushup(int rt,int mid){
	wsum[rt]=wsum[lson]+wsum[rson];
	bsum[rt]=bsum[lson]+bsum[rson];
	for(int i=1;i<=n;i++){
		f[i]=lfa[lson][i];f[i+n]=rfa[lson][i];
		f[i+2*n]=lfa[rson][i]+2*n;f[i+3*n]=rfa[rson][i]+2*n;
	}
	for(int i=1;i<=n;i++)
		if(a[mid][i]==a[mid+1][i]){
			if(find(i+n,f)!=find(i+2*n,f)){
				f[find(i+n,f)]=f[find(i+2*n,f)];
				if(a[mid][i]==0) wsum[rt]--;
				else bsum[rt]--;
			}
		}
	for(int i=1;i<=n;i++) tmp[find(i,f)]=i;
	for(int i=3*n+1;i<=4*n;i++) tmp[find(i,f)]=i-2*n;
	for(int i=1;i<=n;i++){
		lfa[rt][i]=tmp[find(i,f)];
		rfa[rt][i]=tmp[find(i+3*n,f)];
	}
}

void build(int l,int r,int rt){
	if(l == r){
		for(int i=1;i<=n;i++) lfa[rt][i]=i;
		for(int i=1;i<=n;i++){
			if(a[l][i]==0) wsum[rt]++;
			else bsum[rt]++;
			if(a[l][i-1]==a[l][i]){
				lfa[rt][find(i-1,lfa[rt])]=i;
				if(a[l][i]==0) wsum[rt]--;
				else bsum[rt]--;
			}
			rfa[rt][i]=lfa[rt][i];
		}
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,lson);
	build(mid+1,r,rson);
	pushup(rt,mid);
}

void modify(int x,int l,int r,int rt){
	if(l == r){
		wsum[rt]=bsum[rt]=0;
		for(int i=1;i<=n;i++) lfa[rt][i]=i;
		for(int i=1;i<=n;i++){
			if(a[l][i]==0) wsum[rt]++;
			else bsum[rt]++;
			if(a[l][i-1]==a[l][i]){
				lfa[rt][find(i-1,lfa[rt])]=i;
				if(a[l][i]==0) wsum[rt]--;
				else bsum[rt]--;
			}
			rfa[rt][i]=lfa[rt][i];
		}
		return ;
	}
	int mid=(l+r)>>1;
	if(x <= mid) modify(x,l,mid,lson);
	else modify(x,mid+1,r,rson);
	pushup(rt,mid);
}

int main()
{
	n=read();
	for(int i=1;i<=n;i++) a[i][0]=-1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) a[i][j]=read();
	build(1,n,1);
	m=read();
	int x,y;
	while(m--){
		x=read(),y=read();
		a[x][y]^=1;modify(x,1,n,1);
		printf("%d %d
",bsum[1],wsum[1]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/owencodeisking/p/10228904.html