zoukankan      html  css  js  c++  java
  • P4121 [WC2005]双面棋盘 线段树分治+可撤销并查集

    题意:

    戳这里

    分析:

    动态维护图的连通性:

    常见的离线做法有两种 , LCT线段树分治

    其中线段树分治常见的有两种:

    1. 操作之间独立
    2. 操作不独立,这种情况下大部分是按时间进行分治

    对于这个题,我们要维护两种颜色的连通块个数,很容易想到并查集,但是并查集不支持删边/kk,那我们换个思路,我们把删边操作看成出现一段时间,这样只需要一个可撤销并查集

    举个栗子:

    (x,y) 这个点由 白色 变成 黑色,首先把它周围的白点的边和它断开,再把周围黑色点和它合并,维护连通块个数

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 1e5+5;
    	int n,m,tot;
    	int col[205][205],frm[maxn<<3],to[maxn<<3],lst[maxn<<3],cnt[maxn];
    	int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
    	map<pii,int> pid;
    	struct info
    	{
    		int col,u,v;
    		info(){}
    		info(int col,int u,int v):col(col),u(u),v(v){}
    	};
    	vector<info> t[maxn<<2];
    	
    	struct dsu
    	{
    		int top,cnt;
    		int fa[maxn],siz[maxn],st[maxn];
    		
    		void init(int num)
    		{
    			for(int i=1;i<=num;i++) fa[i]=i,siz[i]=1;
    		}
    		
    		int find(int x)
    		{
    			return fa[x]==x?x:find(fa[x]);
    		}
    		
    		void merge(int x,int y)
    		{
    			int fx=find(x),fy=find(y);
    			if(fx!=fy)
    			{
    				if(siz[fx]<siz[fy]) swap(fx,fy);
    				st[++top]=fy;cnt++;
    				fa[fy]=fx;siz[fx]+=siz[fy];
    			}
    		}
    		
    		void del(int num)
    		{
    			while(top>num)
    			{
    				siz[fa[st[top]]]-=siz[st[top]];
    				fa[st[top]]=st[top];
    				top--;cnt--;
    			}
    		}
    		
    	}bla,whi;
    	
    	inline int id(int c,int x,int y)
    	{
    		return c*n*n+(x-1)*n+y;
    	}
    	
    	void modify(int rt,int l,int r,int ql,int qr,info x)
    	{
    		if(ql<=l&&r<=qr)
    		{
    			t[rt].pb(x);
    			return ;
    		}
    		int mid=(l+r)>>1;
    		if(ql<=mid) modify(lc,l,mid,ql,qr,x);
    		if(qr>mid) modify(rc,mid+1,r,ql,qr,x);
    	}
    	
    	void add(int x,int y)
    	{
    		if(x>y) swap(x,y);
    		pid[mk(x,y)]=++tot;
    		frm[tot]=x;
    		to[tot]=y;
    	}
    	
    	void link(int x,int y,int tim)
    	{
    		if(x>y) swap(x,y);
    		lst[pid[mk(x,y)]]=tim;
    	}
    	
    	void cut(int c,int x,int y,int tim)
    	{
    		if(x>y) swap(x,y);
    		modify(1,0,m,lst[pid[mk(x,y)]],tim-1,info(c,x,y));
    		lst[pid[mk(x,y)]]=-1;
    	}
    	
    	void solve(int rt,int l,int r)
    	{
    		int top1=bla.top,top2=whi.top;
    		for(auto i:t[rt]) i.col?bla.merge(i.u-n*n,i.v-n*n):whi.merge(i.u,i.v);
    		if(l==r)
    		{
    			if(l) printf("%d %d
    ",n*n-cnt[l]-bla.cnt,cnt[l]-whi.cnt);
    			bla.del(top1);whi.del(top2);
    			return ;
    		}
    		int mid=(l+r)>>1;
    		solve(lc,l,mid);solve(rc,mid+1,r);
    		bla.del(top1);whi.del(top2);
    	}
    	
    	void work()
    	{
    		int x,y,c;
    		memset(lst,-1,sizeof(lst));memset(col,-1,sizeof(col));
    		n=read();bla.init(n*n);whi.init(n*n);
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=n;j++)
    			{
    				col[i][j]=read();
    				cnt[0]+=col[i][j]==0;
    				if(i!=n) add(id(0,i,j),id(0,i+1,j)),add(id(1,i,j),id(1,i+1,j));
    				if(j!=n) add(id(0,i,j),id(0,i,j+1)),add(id(1,i,j),id(1,i,j+1));
    			}
    		}
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=n;j++)
    			{
    				if(i!=n&&col[i][j]==col[i+1][j]) link(id(col[i][j],i,j),id(col[i+1][j],i+1,j),0);
    				if(j!=n&&col[i][j]==col[i][j+1]) link(id(col[i][j],i,j),id(col[i][j+1],i,j+1),0);
    			}
    		}
    		m=read();
    		for(int i=1;i<=m;i++)
    		{
    			x=read();y=read();c=col[x][y];cnt[i]=cnt[i-1];
    			for(int j=0;j<4;j++)
    			{
    				int tx=x+dx[j],ty=y+dy[j];
    				if(col[tx][ty]==c) cut(c,id(c,x,y),id(c,tx,ty),i);
    			}
    			cnt[i]-=c==0;
    			c^=1;col[x][y]^=1;
    			cnt[i]+=c==0;
    			for(int j=0;j<4;j++)
    			{
    				int tx=x+dx[j],ty=y+dy[j];
    				if(col[tx][ty]==c) link(id(c,x,y),id(c,tx,ty),i);
    			}
    		}
    		for(int i=1;i<=tot;i++) if(lst[i]!=-1) cut(frm[i]>n*n,frm[i],to[i],m+1);
    		solve(1,0,m);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    Ansible专题整理
    前端基础之JQuery
    Three.js开发指南---创建,加载高级网格和几何体(第八章)
    Three.js开发指南---粒子和粒子系统(第七章)
    Three.js开发指南---使用高级几何体和二元操作(第六章)
    Three.js开发指南---学习使用几何体(第五章)
    Three.js开发指南---使用three.js的材质(第四章)
    Three.js开发指南---使用three.js里的各种光源(第三章)
    Three.js开发指南---使用构建three.js的基本组件(第二章)
    -Three.js开发指南---用three.js创建你的第一个三维场景(第一章)
  • 原文地址:https://www.cnblogs.com/youth518/p/14278007.html
Copyright © 2011-2022 走看看