BZOJ 1453 [Wc]Dface双面棋盘

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100009;
const int oo=1000000000;
int dx[5]={0,1,0,0,-1};
int dy[5]={0,0,-1,1,0};

int n,TT;

int cntedge;
int fa[maxn]={0},ch[maxn][2]={0},siz[maxn],ky[maxn]={0},mn[maxn]={0},mnp[maxn]={0},rev[maxn]={0};
inline int son(int x){
	if(ch[fa[x]][0]==x)return 0;
	else return 1;
}
inline void pushup(int x){
	mn[x]=ky[x];mnp[x]=x;
	if(mn[ch[x][0]]<mn[x]){
		mn[x]=mn[ch[x][0]];
		mnp[x]=mnp[ch[x][0]];
	}
	if(mn[ch[x][1]]<mn[x]){
		mn[x]=mn[ch[x][1]];
		mnp[x]=mnp[ch[x][1]];
	}
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+(ky[x]==oo);
}
inline void pushdown(int x){
	if(rev[x]){
		rev[ch[x][0]]^=1;
		rev[ch[x][1]]^=1;
		rev[x]^=1;
		swap(ch[x][0],ch[x][1]);
	}
}
inline bool isroot(int x){
	return (ch[fa[x]][0]!=x)&&(ch[fa[x]][1]!=x);
}
void Downfa(int x){
	if(!isroot(x))Downfa(fa[x]);
	pushdown(x);
}

inline void Rotate(int x){
	int y=fa[x];
	int z=fa[y];
	int b=son(x),c=son(y);
	int a=ch[x][b^1];
	if(!isroot(y))ch[z][c]=x;
	fa[x]=z;
	if(a)fa[a]=y;
	ch[y][b]=a;
	fa[y]=x;ch[x][b^1]=y;
	pushup(y);pushup(x);
}
void Splay(int x){
	Downfa(x);
	while(!isroot(x)){
		int y=fa[x];
		if(isroot(y)){
			Rotate(x);
		}else{
			if(son(x)==son(y)){
				Rotate(y);Rotate(x);
			}else{
				Rotate(x);Rotate(x);
			}
		}
	}
}

void Acc(int x){
	for(int t=0;x;t=x,x=fa[x]){
		Splay(x);ch[x][1]=t;pushup(x);
	}
}
void Makeroot(int x){
	Acc(x);Splay(x);rev[x]^=1;
}
void Lin(int x,int y){
	Makeroot(x);fa[x]=y;
}
void Cut(int x,int y){
	Makeroot(x);Acc(y);Splay(y);
	fa[ch[y][0]]=0;ch[y][0]=0;pushup(y);
}
int Getroot(int x){
	Acc(x);Splay(x);
	while(ch[x][0])x=ch[x][0];
	return x;
}
int GetminEdge(int x,int y){
	Makeroot(x);Acc(y);Splay(y);
	return mnp[y];
}

int p[209][209];
int OG[209][209];
int a[209][209];
int opt[maxn][3];
int ans[maxn][3];
int nex[maxn];
int tong[maxn];
int nowans;

void MakeLink(int x,int y){
	int lastest=min(tong[x],tong[y]);
	if(Getroot(x)!=Getroot(y)){
//		cout<<x<<' '<<y<<endl;
		--nowans;++cntedge;
		mn[cntedge]=ky[cntedge]=lastest;
		mnp[cntedge]=cntedge;
		Lin(x,cntedge);Lin(y,cntedge);
	}else{
		int tm=GetminEdge(x,y);
//		cout<<tm<<endl;
		if(ky[tm]>=lastest)return;
		Cut(x,tm);Cut(y,tm);
		++cntedge;
		mn[cntedge]=ky[cntedge]=lastest;
		mnp[cntedge]=cntedge;
//		cout<<x<<' '<<y<<endl;
		Lin(x,cntedge);Lin(y,cntedge);
	}
}

int HaveEdge(int x,int y){
	if(Getroot(x)!=Getroot(y))return 0;
	Makeroot(x);Acc(y);
	Splay(y);
	int tm=siz[ch[y][0]];
	Splay(x);
	int tm2=siz[ch[x][0]];
	if(tm2==tm-1)return 1;
	else return 0;
}

void MakeCut(int x,int y){
	if(!HaveEdge(x,y))return;
	Cut(x,y);
	nowans++;
}

inline int Isright(int x,int y){
	if((x<=0)||(y<=0))return 0;
	if((x>n)||(y>n))return 0;
	return 1;
}

void Sol1(){
	ky[0]=mn[0]=oo;
	nowans=0;
	cntedge=n*n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			a[i][j]=OG[i][j];
			if(a[i][j])++nowans;
		}
	}
	for(int i=1;i<=n*n;++i)tong[i]=oo-1;
	for(int i=1;i<=n*n;++i){
		siz[i]=1;mn[i]=ky[i]=oo;
	}
	for(int i=TT;i>=1;--i){
		tong[p[opt[i][1]][opt[i][2]]]=i;
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(a[i][j]!=1)continue;
			for(int k=1;k<=2;++k){
				int x=i+dx[k];
				int y=j+dy[k];
				if(!Isright(x,y))continue;
				if(a[x][y]!=1)continue;
				MakeLink(p[x][y],p[i][j]);
			}
		}
	}
	for(int i=1;i<=TT;++i){
		int x=opt[i][1],y=opt[i][2];
		if(a[x][y]==0){
			a[x][y]=1;
			tong[p[x][y]]=nex[i];
			++nowans;
			for(int k=1;k<=4;++k){
				int xx=x+dx[k];
				int yy=y+dy[k];
				if(!Isright(xx,yy))continue;
				if(!a[xx][yy])continue;
				MakeLink(p[x][y],p[xx][yy]);
			}
		}else{
			a[x][y]=0;
			tong[p[x][y]]=nex[i];
			for(int k=1;k<=4;++k){
				int xx=x+dx[k];
				int yy=y+dy[k];
				if(!Isright(xx,yy))continue;
				if(!a[xx][yy])continue;
				MakeCut(p[x][y],p[xx][yy]);
			}
			--nowans;
		}
		ans[i][1]=nowans;
	}
}
void Sol2(){
	memset(fa,0,sizeof(fa));
	memset(ch,0,sizeof(ch));
	memset(ky,0,sizeof(ky));
	memset(mn,0,sizeof(mn));
	memset(mnp,0,sizeof(mnp));
	memset(rev,0,sizeof(rev));
	ky[0]=mn[0]=oo;
	nowans=0;
	cntedge=n*n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			a[i][j]=OG[i][j];
			if(a[i][j]==0)++nowans;
		}
	}
	for(int i=1;i<=n*n;++i)tong[i]=oo-1;
	for(int i=1;i<=n*n;++i){
		siz[i]=1;mn[i]=ky[i]=oo;
	}
	for(int i=TT;i>=1;--i){
		tong[p[opt[i][1]][opt[i][2]]]=i;
	}
	
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(a[i][j])continue;
			for(int k=1;k<=2;++k){
				int x=i+dx[k];
				int y=j+dy[k];
				if(!Isright(x,y))continue;
				if(a[x][y])continue;
//				cout<<"fucking "<<p[x][y]<<' '<<p[i][j]<<endl;
				MakeLink(p[x][y],p[i][j]);
			}
		}
	}
//	cout<<"begin"<<endl;
	for(int i=1;i<=TT;++i){
		int x=opt[i][1],y=opt[i][2];
		if(a[x][y]){
			a[x][y]=0;
			tong[p[x][y]]=nex[i];
			++nowans;
			for(int k=1;k<=4;++k){
				int xx=x+dx[k];
				int yy=y+dy[k];
				if(!Isright(xx,yy))continue;
				if(a[xx][yy])continue;
				MakeLink(p[x][y],p[xx][yy]);
			}
		}else{
			a[x][y]=1;
			tong[p[x][y]]=nex[i];
			for(int k=1;k<=4;++k){
				int xx=x+dx[k];
				int yy=y+dy[k];
				if(!Isright(xx,yy))continue;
				if(a[xx][yy])continue;
				MakeCut(p[x][y],p[xx][yy]);
			}
			--nowans;
		}
		ans[i][2]=nowans;
	}
}

int main(){
	scanf("%d",&n);
	for(int cnt=0,i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			p[i][j]=++cnt;
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			scanf("%d",&OG[i][j]);
		}
	}
	scanf("%d",&TT);
	for(int i=1;i<=TT;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		opt[i][1]=x;opt[i][2]=y;
		if(tong[p[x][y]])nex[tong[p[x][y]]]=i;
		tong[p[x][y]]=i;
	}
	for(int i=1;i<=TT;++i)if(nex[i]==0)nex[i]=oo-1;
	
	Sol1();
	Sol2();
	
	for(int i=1;i<=TT;++i)printf("%d %d\n",ans[i][1],ans[i][2]);
	return 0;
}

 

  

题解:

动态图的连通性问题

离线下来,维护边权为删除时间的最大生成树

在知乎上看了一篇很好的文章,先留坑,以后补上

 

posted @ 2018-03-14 17:43  ws_zzy  阅读(188)  评论(0编辑  收藏  举报