您的位置:首页 > 其它

[BZOJ1453][Wc]Dface双面棋盘(lct)

2017-04-01 16:54 302 查看

题目描述

传送门

题解

这题好麻烦啊…

相当于是有一堆砍边和加边的操作,然后询问联通块数量

维护一棵以删除时间为权值的最大生成树,这样可以保证砍断一条边一定是联通块数量-1,加一条边一定是联通块数量+1

其余的做法实际上是和二分图那道题是一样的

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;

int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};
int n,m,sz,color[205][205],c[205][205],cnt;
struct data
{
int x,y,t,d,id,opt,c;
bool operator < (const data &a) const
{
return x<a.x||x==a.x&&y<a.y;
}
}e[200005],opr[10005];
map <data,int> mp;
int f[200005],ch[200005][2],minn[200005],rev[200005],stack[200005],val[200005];
int re[200005],pt[200005],l[200005],r[200005],tree[200005];
int ans[2];

int read()
{
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
//---------------------------init----------------------------------
int eid(int a,int b,int c,int d)
{
if (a==c)
{
if (b>d) swap(b,d);
return (a-1)*(n-1)+b;
}
else
{
if (a>c) swap(a,c);
return n*(n-1)+(a-1)*n+b;
}
}
int cmptopt(data a,data b)
{
return a.t<b.t||(a.t==b.t&&a.opt<b.opt);
}
//----------------------------lct----------------------------------
bool isroot(int x)
{
return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
}
int get(int x)
{
return ch[f[x]][1]==x;
}
void update(int x)
{
int loc=x;
if (ch[x][0])
{
if (val[minn[ch[x][0]]]<val[loc])
loc=minn[ch[x][0]];
}
if (ch[x][1])
{
if (val[minn[ch[x][1]]]<val[loc])
loc=minn[ch[x][1]];
}
minn[x]=loc;
}
void pushdown(int x)
{
if (x&&rev[x])
{
if (ch[x][0]) rev[ch[x][0]]^=1;
if (ch[x][1]) rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
}
void rotate(int x)
{
int old=f[x],oldf=f[old],wh=get(x);
if (!isroot(old)) ch[oldf][ch[oldf][1]==old]=x;
f[x]=oldf;
ch[old][wh]=ch[x][wh^1];
if (ch[old][wh]) f[ch[old][wh]]=old;
ch[x][wh^1]=old;
f[old]=x;
update(old);
update(x);
}
void splay(int x)
{
int top=0;stack[++top]=x;
for (int i=x;!isroot(i);i=f[i]) stack[++top]=f[i];
for (int i=top;i;--i) pushdown(stack[i]);

for (int fa;!isroot(x);rotate(x))
if (!isroot(fa=f[x]))
rotate((get(x)==get(fa))?fa:x);
}
void access(int x)
{
int t=0;
for (;x;t=x,x=f[x])
{
splay(x);
ch[x][1]=t;
update(x);
}
}
void reverse(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
int find(int x)
{
access(x);
splay(x);
while (ch[x][0]) x=ch[x][0];
return x;
}
void link(int x,int y)
{
reverse(x);
f[x]=y;
}
void cut(int x,int y)
{
reverse(x);
access(y);
splay(y);
ch[y][0]=f[x]=0;
}
//--------------------------operation------------------------------
void add(int i,int cc)
{
int x=e[i].x,y=e[i].y,d=e[i].d,id=e[i].id;
if (find(x)==find(y))
{
reverse(x);
access(y);
splay(y);
int loc=minn[y];
if (d<=val[loc]) return;
cut(loc,l[loc]);
cut(loc,r[loc]);
tree[re[loc]]=0;
}
else --ans[cc];
++sz;val[sz]=d;
re[sz]=id;pt[id]=sz;tree[id]=1;
l[sz]=x,r[sz]=y;
link(x,sz);
link(y,sz);
}
void del(int i)
{
int x=e[i].x,y=e[i].y,id=e[i].id;
cut(x,pt[id]);
cut(y,pt[id]);
tree[id]=0;
}

//---------------------------main----------------------------------
int main()
{
n=read();
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
color[i][j]=c[i][j]=read();
++ans[c[i][j]];
}
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
int num=(i-1)*n+j,cc=color[i][j];
if (j!=n&&color[i][j+1]==cc)
e[++cnt].x=num,e[cnt].y=num+1,e[cnt].t=0,e[cnt].id=eid(i,j,i,j+1),e[cnt].opt=1,e[cnt].c=cc;
if (i!=n&&color[i+1][j]==cc)
e[++cnt].x=num,e[cnt].y=num+n,e[cnt].t=0,e[cnt].id=eid(i,j,i+1,j),e[cnt].opt=1,e[cnt].c=cc;
}

m=read();
for (int i=1;i<=m;++i)
{
int x=read(),y=read();
opr[i].x=x,opr[i].y=y;
int num=(x-1)*n+y;
for (int j=0;j<4;++j)
{
int nx=x+dx[j],ny=y+dy[j],nnum=(nx-1)*n+ny;
if (nx<=0||ny<=0||nx>n||ny>n) continue;
if (c[x][y]==c[nx][ny])
e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=-1;
else
e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=1;
}
c[x][y]^=1;
}

sort(e+1,e+cnt+1,cmptopt);
for (int i=1;i<=cnt;++i) e[i].d=m+1;
mp.clear();
for (int i=cnt;i>=1;--i)
{
if (e[i].x>e[i].y) swap(e[i].x,e[i].y);
if (mp[e[i]]) e[i].d=mp[e[i]];
mp[e[i]]=e[i].t;
}
sz=n*n;
memset(val,127,sizeof(val));
int now=1;
for (;now<=cnt&&e[now].t<=0;++now)
add(now,e[now].c);
for (int i=1;i<=m;++i)
{
int x=opr[i].x,y=opr[i].y;
int cc=color[x][y];
for (;now<=cnt&&e[now].t<=i;++now)
if (e[now].opt==-1)
{
if (!tree[e[now].id]) continue;
del(now);
++ans[cc];
}
else add(now,cc^1);
--ans[cc];
++ans[cc^1];
color[x][y]^=1;
printf("%d %d\n",ans[1],ans[0]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: