BZOJ 1453 Wc2005 Dface双面棋盘 Link-Cut-Tree
来源:互联网 发布:mac下hadoop安装配置 编辑:程序博客网 时间:2024/04/28 09:50
题目大意:给定一张网格图,每个点有黑色和白色,同色相邻的点之间连边,每次反转一个点的颜色并输出黑色和白色的联通块个数
《论科技不发达的危害》
这显然是个动态图问题,由于不强制在线,我们用Link-Cut-Tree维护边删除时间的最大生成树就可以了
时间复杂度
常数巨大
#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
- BZOJ 1453 Wc2005 Dface双面棋盘 Link-Cut-Tree
- 【WC2005】【BZOJ1453】Dface双面棋盘
- 【BZOJ】【P1453】【WC2005】【Dface双面棋盘】【题解】【线段树+并查集】
- [Wc]Dface双面棋盘
- [CDQ分治 并查集] BZOJ 1453 [Wc]Dface双面棋盘
- WC 2005 dface 双面棋盘
- BZOJ1453: [Wc]Dface双面棋盘
- bzoj1453: [Wc]Dface双面棋盘
- 1453: [Wc]Dface双面棋盘 (线段树+并茶几)
- BZOJ1453——[Wc]Dface双面棋盘
- [BZOJ1453][Wc]Dface双面棋盘(lct)
- bzoj 2049(link cut tree)
- bzoj 2157(link cut tree)
- bzoj 1180(link cut tree)
- bzoj 2631(link cut tree)
- BZOJ 2002 Link-Cut Tree
- BZOJ 2631 Tree Link-Cut-Tree(LCT)
- BZOJ 3282 Tree Link-Cut-Tree(LCT)
- dom4j 创建xml
- 分布式系统
- JVM学习笔记(三)------内存管理和垃圾回收
- Effective C++——条款26(第5章)
- 从一道面试题谈linux下fork的运行机制
- BZOJ 1453 Wc2005 Dface双面棋盘 Link-Cut-Tree
- Js的Url中传递中文参数乱码,如何获取Url中参数问题
- 获取App中的签名信息
- oracle 游标之 定义变量
- windows7环境下theano安装
- java面试题
- 互联网协议入门
- JVM学习笔记(四)------内存调优
- 关于JDK 1.6与JDK1.6+ 中的subString 讨论