传送门: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