【BZOJ】1453: [Wc]Dface双面棋盘-LCT

传送门:bzoj1453


题解

L C T LCT LCT维护图的连通性。

注意断环时必须要贪心 c u t cut cut其后断开时间最早的边,否则不能保证正确性。

那么需要预处理出每次操作中断和连上的环,并维护黑白联通块个数(一个复杂的大模拟)。。。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=205,M=4e4+5,inf=0x7f7f7f7f;

int n,m,nn,ap[M*3],col[N][N],a[N][N],dr[N][N][4],tot,cot;
int nb,nw,qx[10005],qy[10005];
bool exi[M*3];

const int dx[5]={-1,1,0,0};
const int dy[5]={0,0,-1,1};

struct qr{
  int id,op,tim,nt;
  qr(int id_=0,int op_=0,int tim_=0,int nt_=0):id(id_),op(op_),tim(tim_),nt(nt_){};
  bool operator <(const qr&ky)const{
       return tim!=ky.tim?(tim<ky.tim):(op<ky.op);
  }
}q[M<<2];
struct mg{int x,dir;};

char cp;
inline void rd(int &x)
{
	cp=getchar();x=0;
	for(;!isdigit(cp);cp=getchar());
	for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}

namespace LCT{
    #define lc(x) t[(x)].ch[0]
    #define rc(x) t[(x)].ch[1]
    #define F(x) t[(x)].fa
    #define notrt(x) ((F((x))!=0)&&((lc(F((x)))==x)||(rc(F((x)))==x)))

	int stk[M*3],top;
	
	struct node{
	   int fa,ch[2],rv,val,mn,id;
	   node(){val=mn=inf;}
	}t[M*3];
    
    inline void pushup(int x)
    {
    	t[x].mn=t[x].val;t[x].id=x;
    	if(t[lc(x)].mn<t[x].mn) t[x].mn=t[lc(x)].mn,t[x].id=t[lc(x)].id;
    	if(t[rc(x)].mn<t[x].mn) t[x].mn=t[rc(x)].mn,t[x].id=t[rc(x)].id;
    }
    
    inline void pushdown(int x)
    {
    	if(!t[x].rv) return;t[x].rv=0;
    	if(lc(x)) t[lc(x)].rv^=1,swap(lc(lc(x)),rc(lc(x)));
    	if(rc(x)) t[rc(x)].rv^=1,swap(lc(rc(x)),rc(rc(x)));
    }
    
    inline void rot(int x)
    {
    	int y=F(x),z=F(y),dr=((rc(y)==x));
    	t[y].ch[dr]=t[x].ch[dr^1];if(t[y].ch[dr]) F(t[y].ch[dr])=y;
    	F(x)=z;if(notrt(y)) t[z].ch[(rc(z)==y)]=x;
    	F(y)=x;t[x].ch[dr^1]=y;pushup(y);
    }
    
    inline void splay(int x)
    {
    	int y,z;
    	for(top=0,y=x;notrt(y);y=F(y)) stk[++top]=y;
		pushdown(y);for(;top;--top) pushdown(stk[top]);
    	for(;notrt(x);rot(x)){
    		y=F(x);z=F(y);
    		if(notrt(y)) ((lc(y)==x)^(lc(z)==y))?rot(x):rot(y);
    	}
    	pushup(x);
    }
    
    inline void setrs(int x,int y){splay(x);rc(x)=y;pushup(x);}
    inline void access(int x){for(setrs(x,0);F(x);x=F(x)) setrs(F(x),x);}
    inline void mkrt(int x){access(x);splay(x);t[x].rv^=1;swap(lc(x),rc(x));}
    inline int fdrt(int x){for(;F(x);x=F(x));for(;lc(x);x=lc(x));return x;}
    inline bool iscon(int x,int y){return fdrt(x)==fdrt(y);}
    inline void lk(int x,int y){mkrt(x);F(x)=y;}
    inline void cut(int x,int y){mkrt(x);access(y);splay(y);lc(y)=F(x)=0;pushup(y);}
    
}

using namespace LCT;

inline void init()
{
	memset(ap,0xff,sizeof(ap));
	int i,j,k,x,y,ix,iy;rd(n);nn=n*n;cot=nn;
	for(i=1;i<=n;++i)
	 for(j=1;j<=n;++j){
	    rd(col[i][j]);a[i][j]=col[i][j];if(a[i][j]) nb++;else nw++;
	 }
	for(i=1;i<=n;++i)
	 for(j=1;j<=n;++j){
	    ++cot;dr[i][j][1]=dr[i+1][j][0]=cot+nn;dr[i][j][3]=dr[i][j+1][2]=cot;
		if(j<n && col[i][j]==col[i][j+1]) ap[cot]=0;
		if(i<n && col[i][j]==col[i+1][j]) ap[cot+nn]=0;
	 }
	rd(m); 
    for(i=1;i<=m;++i){
   	  rd(x);rd(y);qx[i]=x;qy[i]=y;a[x][y]^=1;
   	  for(j=0;j<4;++j){
		 k=dr[x][y][j];ix=x+dx[j];iy=y+dy[j];if(ix>0 && ix<=n && iy>0 && iy<=n){
		 	if(a[x][y]==a[ix][iy]) ap[dr[x][y][j]]=i;
		    else{q[++tot]=qr(k,1,ap[k],i);q[++tot]=qr(k,0,i,0);ap[k]=-1;}
		 }
   	  }
   }
   for(i=nn+1;i<=cot+nn;++i) if(~ap[i]) q[++tot]=qr(i,1,ap[i],1e9);
   sort(q+1,q+tot+1);
}

inline mg trs(int x){return (x<=nn+nn)?(mg){x-nn,0}:(mg){x-nn-nn,1};}

inline void ad(int id,int vl)
{
	register mg tp=trs(id);t[id].val=t[id].mn=vl;
	int x=tp.x,ix=x+(tp.dir?n:1);
	if(iscon(x,ix)){
		mkrt(x);access(ix);splay(ix);if(t[ix].mn>=vl) return;int y=t[ix].id;
		tp=trs(y);exi[y]=false;cut(tp.x,y);cut(tp.x+(tp.dir?n:1),y);
		
	}else {if(col[(x-1)/n+1][(x-1)%n+1]) nb--;else nw--;}
	lk(x,id);lk(id,ix);exi[id]=true;
}

void del(int id,int cl)
{
	if(!exi[id]) return;exi[id]=false;
	register mg tp=trs(id);if(cl) nb++;else nw++;
	cut(tp.x,id);cut(tp.x+(tp.dir?n:1),id);
}

inline void sol()
{
	int i,j,cl;
	for(j=1;j<=tot && q[j].tim==0;++j) ad(q[j].id,q[j].nt);
    for(i=1;i<=m;++i){
   	    cl=col[qx[i]][qy[i]];col[qx[i]][qy[i]]^=1;
   	    if(cl) nb--,nw++;else nw--,nb++;
		for(;j<=tot && q[j].tim==i;++j){
   	   	    if(q[j].op) ad(q[j].id,q[j].nt);
		    else del(q[j].id,cl);
   	    }
  	    printf("%d %d\n",nb,nw);
    }
}

int main(){
    init();sol();
	return 0;
}

调试很久后发现的问题:

p1:
mkrt中:t[x].rv^=1后没有swap(lc(x),rc(x))
s1:
注意标记同步 
p2:
#define notrt(x) ((F((x))!=0)&&((lc(F((x)))==x)||(rc(F((x)))==x)))
中括号匹配错误 
s2:
先单独放一行匹配好括号再define 

注意: 
inline int fdrt(int x){for(;F(x);x=F(x));for(;lc(x);x=lc(x));return x;}
不能写成: 
{for(;F(x);x=F(x));for(;lc(x);x=lc(x));return x;}
因为有些树可能rev过换了根,必须要splay中pushdown 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值