BZOJ 1453 Wc2005 Dface双面棋盘 Link-Cut-Tree

来源:互联网 发布:mac下hadoop安装配置 编辑:程序博客网 时间:2024/04/28 09:50

题目大意:给定一张网格图,每个点有黑色和白色,同色相邻的点之间连边,每次反转一个点的颜色并输出黑色和白色的联通块个数
《论科技不发达的危害》
这显然是个动态图问题,由于不强制在线,我们用Link-Cut-Tree维护边删除时间的最大生成树就可以了
时间复杂度O((n2+m)logn)
常数巨大

#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 40400#define P(x,y) ((x)*n-n+(y))using namespace std;const int dx[]={0,0,1,-1};const int dy[]={1,-1,0,0};int n,m,ans[2];int a[220][220];queue<int> ed[M<<1];pair<int,int> edges[M<<1];pair<int,int> operations[10100];namespace Link_Cut_Tree{    bool Compare(int x,int y)    {        if(!x) return false;        if(!y) return true;        return ed[x].front()<ed[y].front();    }    struct abcd{        abcd *ls,*rs,*fa;        int e,min_e;        bool rev_mark;        abcd(int _);        void Push_Up();        void Push_Down();        void Reverse();    }*null=new abcd(0),*tree[M],*edge[M<<1];    abcd :: abcd(int _)    {        ls=rs=fa=null;        e=min_e=_;        rev_mark=false;    }    void abcd :: Push_Up()    {        min_e=min(min(ls->min_e,rs->min_e,Compare),e,Compare);    }    void abcd :: Push_Down()    {        if(fa->ls==this||fa->rs==this)            fa->Push_Down();        if(rev_mark)        {            ls->Reverse();            rs->Reverse();            rev_mark=false;        }    }    void abcd :: Reverse()    {        swap(ls,rs);        rev_mark^=1;    }    void Zig(abcd *x)    {        abcd *y=x->fa;        y->ls=x->rs;        x->rs->fa=y;        x->rs=y;        x->fa=y->fa;        if(y==y->fa->ls)            y->fa->ls=x;        else if(y==y->fa->rs)            y->fa->rs=x;        y->fa=x;        y->Push_Up();    }    void Zag(abcd *x)    {        abcd *y=x->fa;        y->rs=x->ls;        x->ls->fa=y;        x->ls=y;        x->fa=y->fa;        if(y==y->fa->ls)            y->fa->ls=x;        else if(y==y->fa->rs)            y->fa->rs=x;        y->fa=x;        y->Push_Up();    }    void Splay(abcd *x)    {        x->Push_Down();        while(x->fa->ls==x||x->fa->rs==x)        {            abcd *y=x->fa,*z=y->fa;            if(x==y->ls)            {                if(y==z->ls)                    Zig(y);                Zig(x);            }            else            {                if(y==z->rs)                    Zag(y);                Zag(x);            }        }        x->Push_Up();    }    void Access(abcd *x)    {        abcd *y=null;        while(x!=null)        {            Splay(x);            x->rs=y;            x->Push_Up();            y=x;x=x->fa;        }    }    void Move_To_Root(abcd *x)    {        Access(x);        Splay(x);        x->Reverse();    }    abcd* Find_Root(abcd *x)    {        while(x->fa!=null)            x=x->fa;        return x;    }    bool Connect(abcd *x,abcd *y)    {        Access(x);        Splay(x);        bool re=Find_Root(y)==x;        Access(y);        return re;    }    void Link(abcd *x,abcd *y)    {        Move_To_Root(x);        x->fa=y;    }    bool Cut(abcd *x,abcd *y)    {        Move_To_Root(x);        Access(y);        Splay(y);        if( y->ls!=x || x->rs!=null )            return false;        y->ls=null;        x->fa=null;        y->Push_Up();        return true;    }}void Cut(int e,bool col){    using namespace Link_Cut_Tree;    int x=edges[e].first;    int y=edges[e].second;    if( Cut(edge[e],tree[x]) && Cut(edge[e],tree[y]) )        ++ans[col];    ed[e].pop();}void Link(int e,bool col){    using namespace Link_Cut_Tree;    int x=edges[e].first;    int y=edges[e].second;    if(!Connect(tree[x],tree[y]) )    {        Link(edge[e],tree[x]);        Link(edge[e],tree[y]);        --ans[col];        return ;    }    Move_To_Root(tree[x]);    Access(tree[y]);    Splay(tree[y]);    int _e=tree[y]->min_e;    if( Compare(_e,e) )    {        int _x=edges[_e].first;        int _y=edges[_e].second;        Cut(edge[_e],tree[_x]);        Cut(edge[_e],tree[_y]);        Link(edge[e],tree[x]);        Link(edge[e],tree[y]);    }}int main(){    using namespace Link_Cut_Tree;    int i,j,k,x,y;    cin>>n;    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            scanf("%d",&a[i][j]);    //读入    for(i=1;i<=n;i++)        for(j=1;j<n;j++)            edges[P(i,j)]=pair<int,int>(P(i,j),P(i,j+1));    for(i=1;i<n;i++)        for(j=1;j<=n;j++)            edges[P(i,j)+n*n]=pair<int,int>(P(i,j),P(i+1,j));    //设定每条边对应的两端点    cin>>m;    for(i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        operations[i].first=x;        operations[i].second=y;        for(k=0;k<4;k++)        {            int xx=x+dx[k];            int yy=y+dy[k];            if(!xx||!yy||xx==n+1||yy==n+1)                continue;            if(a[x][y]==a[xx][yy])                ed[min(P(x,y),P(xx,yy))+(k>>1)*n*n].push(i);        }        a[x][y]^=1;    }    //读入数据&&记录每条边的终止时刻    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            for(k=0;k<4;k+=2)            {                int xx=i+dx[k];                int yy=j+dy[k];                if(!xx||!yy||xx==n+1||yy==n+1)                    continue;                if(a[i][j]==a[xx][yy])                    ed[P(i,j)+(k>>1)*n*n].push(m+1);            }    //记录最后没有被删除的边的终止时刻    for(i=1;i<=n*n;i++)        tree[i]=new abcd(0);    for(i=1;i<=n;i++)        for(j=1;j<n;j++)            edge[P(i,j)]=new abcd(P(i,j));    for(i=1;i<n;i++)        for(j=1;j<=n;j++)            edge[P(i,j)+n*n]=new abcd(P(i,j)+n*n);    //申请内存    for(i=m;i;i--)    {        x=operations[i].first;        y=operations[i].second;        a[x][y]^=1;    }    //还原a数组    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            ans[a[i][j]]++;    for(i=1;i<=n;i++)        for(j=1;j<=n;j++)            for(k=0;k<4;k+=2)            {                int xx=i+dx[k];                int yy=j+dy[k];                if(!xx||!yy||xx==n+1||yy==n+1)                    continue;                if(a[i][j]==a[xx][yy])                    Link(P(i,j)+(k>>1)*n*n,a[i][j]);            }    //统计初始答案&&连接初始的边    for(i=1;i<=m;i++)    {        x=operations[i].first;        y=operations[i].second;        for(k=0;k<4;k++)        {            int xx=x+dx[k];            int yy=y+dy[k];            if(!xx||!yy||xx==n+1||yy==n+1)                continue;            if(a[x][y]==a[xx][yy])                Cut(min(P(x,y),P(xx,yy))+(k>>1)*n*n,a[x][y]);        }        ans[a[x][y]]--;        a[x][y]^=1;        ans[a[x][y]]++;        for(k=0;k<4;k++)        {            int xx=x+dx[k];            int yy=y+dy[k];            if(!xx||!yy||xx==n+1||yy==n+1)                continue;            if(a[x][y]==a[xx][yy])                Link(min(P(x,y),P(xx,yy))+(k>>1)*n*n,a[x][y]);        }        printf("%d %d\n",ans[1],ans[0]);    }    return 0;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 加油卡没有密码加油后锁住怎么办 个人怎么办中石化油卡怎么开公司票 中石化副卡挂失后钱怎么办 中石化的加油卡丢了怎么办 得仕卡过期3年了怎么办 如果在超市买到过期商品怎么办 华润万家买的豆干过期了吃了怎么办 华润万家购物卡过期了怎么办 杜鹃花水浇多了树叶都掉了怎么办 游客行程因天气原因无法进行怎么办 携程旅游途中提前结束行程怎么办 小区附近商家卖东西很吵怎么办? 小区门口卖东西的喇叭太吵怎么办 我老婆是二婚带的小孩怎么办户口 ck手表带了脱不下来怎么办 消毒柜开孔尺寸高度太高了怎么办 苏宁易购买的东西比专卖店贵怎么办 手机打字键盘上没有语音功能怎么办 网贷催收发语音侮辱人怎么办 康力无机房电梯到楼层不关门怎么办 档案工龄少算了工资领开了怎么办 别人骚扰我打电话报警人走了怎么办 因外借医保卡被香港保险拒保怎么办 医保和社保断了一个月怎么办 苹果8呼叫受限请勿越权使用怎么办 药物储存2~8度没冰箱怎么办 利仁分体电饼铛做饼熟的慢怎么办 闲鱼买的东西自提有问题怎么办 老板油烟机的表层的膜掉了怎么办 给老板打工老板跑路了怎么办 公司要业务员承担客户的欠款怎么办 从自己公司出去抢自己客户怎么办? 在苏宁买东西买贵了怎么办 苏宁购物小票不见了未提货怎么办 结痂的地方扣掉了颜色不一样怎么办 实体店买手机不给发票怎么办 小孩学英语字母怎么都记不住怎么办 聊客老是提示网络连接失败怎么办? 天猫购物漏发客服不理怎么办 京东二维码被骗怎么办联系客服号码 京东客服打电话来让自己退款怎么办