您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: