BZOJ1453: [Wc]Dface双面棋盘

来源:互联网 发布:js里取juid 编辑:程序博客网 时间:2024/04/30 19:16

题目

http://www.lydsy.com/JudgeOnline/problem.php?id=1453

题解

线段树上维护奇怪的信息第二题,这道题写的很快,1h,但是因为合并的时候把并查集合并写错了qwqqqq卧槽啊这个时候了我居然还在写错这些、记住是修改根的父亲为根啊(倒)。

思路还是挺简单啦,每个节点开两个200的数组记录两边的连通信息,在一个连通块的标号一样,然后合并的时候,交界处如果颜色相同就认为有一条边然后做并查集合并。并查集也是真的厉害辣,代码很简单啦(可能是被上一道题虐傻了)。

代码

//QWsin#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=200+10;int col[maxn][maxn];int p[maxn*4],id[maxn*4];int findset(int x){return p[x]==x?x:p[x]=findset(p[x]);}int n;struct G{//存放连通性     int l,r;    int cnt1,cnt2,T,pl[maxn],pr[maxn];    //维护连通块个数,pl左pr右并查集,T记录边界上并查集编号最大值(方便合并)     //cnt1 black cnt2 white    G(int l=0,int r=0):l(l),r(r){        cnt1=cnt2=0;memset(pl,0,sizeof pl);        memset(pr,0,sizeof pr);    }    G operator + (const G &rhs)const{        G ret(l,rhs.r);        int C1=cnt1+rhs.cnt1;        int C2=cnt2+rhs.cnt2;        for(int i=1;i<=T+rhs.T;++i) p[i]=i,id[i]=0;        //右边的连通块编号统一加上左边的T值,合并为一个图再连边        for(int i=1;i<=n;++i) if(col[i][r]==col[i][r+1])        {            int p1=findset(pr[i]);            int p2=findset(rhs.pl[i]+T);            if(p1!=p2){                p[p2]=p1;//原来把并查集这里合并写错了(捂脸)                if(col[i][r]) --C1;                else --C2;            }        }        //离散一下编号,因为都不大所以可以直接用数组记离散后对应的编号        int rank=0;ret.cnt1=C1;ret.cnt2=C2;        for(int i=1;i<=n;++i){            int p1=findset(pl[i]);            int p2=findset(rhs.pr[i]+T);            if(!id[p1]){id[p1]=++rank;}            if(!id[p2]){id[p2]=++rank;}            ret.pl[i]=id[p1];            ret.pr[i]=id[p2];        }        ret.T=rank;        return ret;    }    //单独更新pos列的信息     inline void work(int pos)    {        cnt1=cnt2=0;        for(int i=1;i<=n;++i)        {            if(i==1||col[i][pos]!=col[i-1][pos])            {                if(col[i][pos]) ++cnt1;                else ++cnt2;            }            pl[i]=pr[i]=cnt1+cnt2;        }        T=cnt1+cnt2;    }};struct Node{    G g;    Node *lc,*rc;       Node(int l,int r){lc=rc=NULL;g=G(l,r);}    inline void up(){g=lc->g+rc->g;}}*root;#define mid ((l+r)>>1)void build(Node* &p,int l,int r){    p=new Node(l,r);    if(l==r) {p->g.work(l);return ;}    build(p->lc,l,mid);    build(p->rc,mid+1,r);    p->up();}void updata(Node* p,int l,int r,int pos){    if(l==r){p->g.work(l);return ;}    if(pos<=mid) updata(p->lc,l,mid,pos);    else updata(p->rc,mid+1,r,pos);     p->up();}int main(){    cin>>n;    for(int i=1;i<=n;++i)        for(int j=1;j<=n;++j)            scanf("%d",col[i]+j);    build(root,1,n);    int m,a,b;cin>>m;       while(m--)    {        scanf("%d%d",&a,&b);        col[a][b]^=1;        updata(root,1,n,b);        printf("%d %d\n",root->g.cnt1,root->g.cnt2);//很良心的一点就是不用写query了    }    return 0;}
0 0
原创粉丝点击