BZOJ1453 WCDface 双面棋盘

来源:互联网 发布:广电网络运维体系建设 编辑:程序博客网 时间:2024/04/24 00:24

1453: [Wc]Dface双面棋盘

Time Limit: 10 Sec  Memory Limit: 64 MB
Description
这里写图片描述
Input
这里写图片描述
Output
这里写图片描述
Sample Input
Sample Output
这里写图片描述
HINT
这里写图片描述
HOME Back

#include<cstdio>#include<cstring>#include<iostream>#include<cstdlib>#include<algorithm>using namespace std;#define MAXN 210int n,m,fa[MAXN<<2],a[MAXN][MAXN],tmp[MAXN<<2];struct Seg_Tree{    int l,r,s0,s1;    int le[MAXN],ri[MAXN],lb[MAXN],rb[MAXN];}tre[MAXN<<2];int Find(int x){    return fa[x]==x?x:fa[x]=Find(fa[x]);}inline int read(int &x){    x=0;int f=1; char c=getchar();    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c-'0');c=getchar();}    x*=f;}#define lc u<<1#define rc u<<1|1inline void UpDate(int u){    tre[u].s0=tre[lc].s0+tre[rc].s0;    tre[u].s1=tre[lc].s1+tre[rc].s1;    memcpy(tre[u].lb,tre[lc].lb,sizeof(tre[u].lb));    memcpy(tre[u].rb,tre[rc].rb,sizeof(tre[u].rb));    for(int i=1;i<=4*n;i++) fa[i]=i;    for(int i=1;i<=n;i++) tre[rc].le[i]+=2*n,tre[rc].ri[i]+=2*n;    for(int i=1;i<=n;i++){        int x=tre[lc].ri[i],y=tre[rc].le[i];        if(Find(x)!=Find(y)&&            tre[lc].rb[i]==tre[rc].lb[i]){            fa[Find(x)]=Find(y);            if(tre[lc].rb[i]) tre[u].s1--;            else tre[u].s0--;        }    }    for(int i=1;i<=n;i++) tre[u].le[i]=Find(tre[lc].le[i]),tre[u].ri[i]=Find(tre[rc].ri[i]);    for(int i=1;i<=n;i++) tmp[i<<1]=tre[u].le[i],tmp[(i<<1)-1]=tre[u].ri[i];    sort(tmp+1,tmp+1+2*n);    int mxdata=unique(tmp+1,tmp+1+2*n)-tmp-1;    for(int i=1;i<=n;i++) tre[u].le[i]=lower_bound(tmp+1,tmp+1+mxdata,tre[u].le[i])-tmp,            tre[u].ri[i]=lower_bound(tmp+1,tmp+1+mxdata,tre[u].ri[i])-tmp;    for(int i=1;i<=n;i++) tre[rc].le[i]-=2*n,tre[rc].ri[i]-=2*n;}void Build(int u,int l,int r){    tre[u].l=l;tre[u].r=r;    if(l==r){        int tot=0;        for(int i=1;i<=n;i++){            if(a[i][l]!=a[i-1][l]){                tot++;                 if(a[i][l]) tre[u].s1++;                else tre[u].s0++;            }            tre[u].le[i]=tre[u].ri[i]=tot;            tre[u].lb[i]=tre[u].rb[i]=a[i][l];        }        return ;    }    int Mid=(l+r)>>1;    Build(u<<1,l,Mid);Build(u<<1|1,Mid+1,r);    UpDate(u);}void Modify(int u,int pos){    if(tre[u].l==tre[u].r){        int tot=0;tre[u].s1=tre[u].s0=0;        for(int i=1;i<=n;i++){            if(a[i][pos]!=a[i-1][pos]){                tot++;                if(a[i][pos]) tre[u].s1++;                else tre[u].s0++;            }            tre[u].le[i]=tre[u].ri[i]=tot;            tre[u].lb[i]=tre[u].rb[i]=a[i][pos];        }        return;    }    int Mid=(tre[u].l+tre[u].r)>>1;    if(pos<=Mid) Modify(u<<1,pos);    else Modify(u<<1|1,pos);    UpDate(u);}int main(){    read(n);    for(int i=1;i<=n;i++){        a[0][i]=-1;        for(int j=1;j<=n;j++) read(a[i][j]);    }    Build(1,1,n);    read(m);    while(m--){        int x,y; read(x); read(y);        a[x][y]^=1;        Modify(1,y);        printf("%d %d\n",tre[1].s1,tre[1].s0);    }    return 0;}

线段树维护左右两端的连通性,合并时用并查集,每次重新标号
加2*N 是为了防止 并查集标号的 重复

原创粉丝点击