#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
",ans[i][1],ans[i][2]);
return 0;
}
题解:
动态图的连通性问题
离线下来,维护边权为删除时间的最大生成树
在知乎上看了一篇很好的文章,先留坑,以后补上