[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\n",bsum[1],wsum[1]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/owencodeisking/p/10228904.html