[BZOJ1453][Wc]Dface双面棋盘(lct)
2017-04-01 16:54
302 查看
题目描述
传送门题解
这题好麻烦啊…相当于是有一堆砍边和加边的操作,然后询问联通块数量
维护一棵以删除时间为权值的最大生成树,这样可以保证砍断一条边一定是联通块数量-1,加一条边一定是联通块数量+1
其余的做法实际上是和二分图那道题是一样的
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> using namespace std; int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0}; int n,m,sz,color[205][205],c[205][205],cnt; struct data { int x,y,t,d,id,opt,c; bool operator < (const data &a) const { return x<a.x||x==a.x&&y<a.y; } }e[200005],opr[10005]; map <data,int> mp; int f[200005],ch[200005][2],minn[200005],rev[200005],stack[200005],val[200005]; int re[200005],pt[200005],l[200005],r[200005],tree[200005]; int ans[2]; int read() { int x=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } //---------------------------init---------------------------------- int eid(int a,int b,int c,int d) { if (a==c) { if (b>d) swap(b,d); return (a-1)*(n-1)+b; } else { if (a>c) swap(a,c); return n*(n-1)+(a-1)*n+b; } } int cmptopt(data a,data b) { return a.t<b.t||(a.t==b.t&&a.opt<b.opt); } //----------------------------lct---------------------------------- bool isroot(int x) { return ch[f[x]][0]!=x&&ch[f[x]][1]!=x; } int get(int x) { return ch[f[x]][1]==x; } void update(int x) { int loc=x; if (ch[x][0]) { if (val[minn[ch[x][0]]]<val[loc]) loc=minn[ch[x][0]]; } if (ch[x][1]) { if (val[minn[ch[x][1]]]<val[loc]) loc=minn[ch[x][1]]; } minn[x]=loc; } void pushdown(int x) { if (x&&rev[x]) { if (ch[x][0]) rev[ch[x][0]]^=1; if (ch[x][1]) rev[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]); rev[x]=0; } } void rotate(int x) { int old=f[x],oldf=f[old],wh=get(x); if (!isroot(old)) ch[oldf][ch[oldf][1]==old]=x; f[x]=oldf; ch[old][wh]=ch[x][wh^1]; if (ch[old][wh]) f[ch[old][wh]]=old; ch[x][wh^1]=old; f[old]=x; update(old); update(x); } void splay(int x) { int top=0;stack[++top]=x; for (int i=x;!isroot(i);i=f[i]) stack[++top]=f[i]; for (int i=top;i;--i) pushdown(stack[i]); for (int fa;!isroot(x);rotate(x)) if (!isroot(fa=f[x])) rotate((get(x)==get(fa))?fa:x); } void access(int x) { int t=0; for (;x;t=x,x=f[x]) { splay(x); ch[x][1]=t; update(x); } } void reverse(int x) { access(x); splay(x); rev[x]^=1; } int find(int x) { access(x); splay(x); while (ch[x][0]) x=ch[x][0]; return x; } void link(int x,int y) { reverse(x); f[x]=y; } void cut(int x,int y) { reverse(x); access(y); splay(y); ch[y][0]=f[x]=0; } //--------------------------operation------------------------------ void add(int i,int cc) { int x=e[i].x,y=e[i].y,d=e[i].d,id=e[i].id; if (find(x)==find(y)) { reverse(x); access(y); splay(y); int loc=minn[y]; if (d<=val[loc]) return; cut(loc,l[loc]); cut(loc,r[loc]); tree[re[loc]]=0; } else --ans[cc]; ++sz;val[sz]=d; re[sz]=id;pt[id]=sz;tree[id]=1; l[sz]=x,r[sz]=y; link(x,sz); link(y,sz); } void del(int i) { int x=e[i].x,y=e[i].y,id=e[i].id; cut(x,pt[id]); cut(y,pt[id]); tree[id]=0; } //---------------------------main---------------------------------- int main() { n=read(); for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) { color[i][j]=c[i][j]=read(); ++ans[c[i][j]]; } for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) { int num=(i-1)*n+j,cc=color[i][j]; if (j!=n&&color[i][j+1]==cc) e[++cnt].x=num,e[cnt].y=num+1,e[cnt].t=0,e[cnt].id=eid(i,j,i,j+1),e[cnt].opt=1,e[cnt].c=cc; if (i!=n&&color[i+1][j]==cc) e[++cnt].x=num,e[cnt].y=num+n,e[cnt].t=0,e[cnt].id=eid(i,j,i+1,j),e[cnt].opt=1,e[cnt].c=cc; } m=read(); for (int i=1;i<=m;++i) { int x=read(),y=read(); opr[i].x=x,opr[i].y=y; int num=(x-1)*n+y; for (int j=0;j<4;++j) { int nx=x+dx[j],ny=y+dy[j],nnum=(nx-1)*n+ny; if (nx<=0||ny<=0||nx>n||ny>n) continue; if (c[x][y]==c[nx][ny]) e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=-1; else e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=1; } c[x][y]^=1; } sort(e+1,e+cnt+1,cmptopt); for (int i=1;i<=cnt;++i) e[i].d=m+1; mp.clear(); for (int i=cnt;i>=1;--i) { if (e[i].x>e[i].y) swap(e[i].x,e[i].y); if (mp[e[i]]) e[i].d=mp[e[i]]; mp[e[i]]=e[i].t; } sz=n*n; memset(val,127,sizeof(val)); int now=1; for (;now<=cnt&&e[now].t<=0;++now) add(now,e[now].c); for (int i=1;i<=m;++i) { int x=opr[i].x,y=opr[i].y; int cc=color[x][y]; for (;now<=cnt&&e[now].t<=i;++now) if (e[now].opt==-1) { if (!tree[e[now].id]) continue; del(now); ++ans[cc]; } else add(now,cc^1); --ans[cc]; ++ans[cc^1]; color[x][y]^=1; printf("%d %d\n",ans[1],ans[0]); } }
相关文章推荐
- BZOJ 1453 Wc2005 Dface双面棋盘 Link-Cut-Tree
- BZOJ1453: [Wc]Dface双面棋盘
- 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集
- BZOJ1453: [Wc]Dface双面棋盘
- BZOJ1453 : [Wc]Dface双面棋盘
- [CDQ分治 并查集] BZOJ 1453 [Wc]Dface双面棋盘
- bzoj 1453 双面棋盘 LCT 并查集
- BZOJ 1453 [WC] 双面棋盘 并查集+线段树暴搞
- 1453: [Wc]Dface双面棋盘 (线段树+并茶几)
- [Wc]Dface双面棋盘
- 【BZOJ】【P1453】【WC2005】【Dface双面棋盘】【题解】【线段树+并查集】
- WC 2005 dface 双面棋盘
- BZOJ1453 WCDface 双面棋盘
- BZOJ1453: [WC2005]Dface双面棋盘
- [BZOJ2594][WC2006]水管局长加强版(LCT+Kruskal)
- BZOJ 2594 [Wc2006]水管局长数据加强版 LCT
- BZOJ2594 [Wc2006]水管局长数据加强版 【LCT维护最小生成树】
- 【bzoj2594】【WC2006】【水管局长加强版】【lct】
- bzoj 2594 [Wc2006]水管局长数据加强版(LCT+最小生成树)
- [BZOJ2594][WC2006][LCT][MST]水管局长数据加强版