BZOJ1453: [Wc]Dface双面棋盘
2017-01-22 09:35
295 查看
题目
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; }
相关文章推荐
- [CDQ分治 并查集] BZOJ 1453 [Wc]Dface双面棋盘
- BZOJ1453: [Wc]Dface双面棋盘
- BZOJ1453 : [Wc]Dface双面棋盘
- 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集
- [BZOJ1453][Wc]Dface双面棋盘(lct)
- BZOJ 1453 Wc2005 Dface双面棋盘 Link-Cut-Tree
- BZOJ 1453 [WC] 双面棋盘 并查集+线段树暴搞
- 1453: [Wc]Dface双面棋盘 (线段树+并茶几)
- BZOJ1453 WCDface 双面棋盘
- WC 2005 dface 双面棋盘
- 【BZOJ】【P1453】【WC2005】【Dface双面棋盘】【题解】【线段树+并查集】
- [Wc]Dface双面棋盘
- BZOJ1453: [WC2005]Dface双面棋盘
- bzoj 1453 双面棋盘 LCT 并查集
- bzoj 1453: [Wc]Dface双面棋盘
- bzoj1453[Wc]Dface双面棋盘
- 【WC2005】【BZOJ1453】Dface双面棋盘
- bzoj1453: [Wc]Dface双面棋盘
- bzoj1453: [Wc]Dface双面棋盘
- BZOJ 2662: [BeiJing wc2012]冻结 分层图 dijkstra