bzoj1453[Wc]Dface双面棋盘
一个$n*n$的棋盘,每个格子为黑色或白色。m次操作,每次修改一个格子的颜色,计算当前有多少黑色四联通块和白色四联通块
$$1 \leq n \leq 200$$
$$1 \leq m \leq 10000$$
当年科技不发达...这明明是LCT一眼题啊喂
设有$x_1$个原来与当前格子同色的连通块与当前格子断开,$x_2$个原来与当前格子不同色的连通块与当前格子连通,那么会增加$x_1-1$个当前格子原来颜色的连通块,减少$x_2-1$个当前格子现在颜色的连通块。
然后我们可以离线然后写一个边权LCT艹过去...
时间复杂度$O((n+m)log_2n)$
但是机房里的小朋友们估计连水管局长数据加长版$[bzoj2594]$都不会做...
于是还是讲一下这道题的在线做法吧
考虑线段树的奇怪用法(参照)
线段树上对应$[l,r]$的节点表示棋盘第$l$行到第$r$行有多少黑色联通块和白色联通块
同时由于这道题是四联通,有可能隔开的两个格是联通的
会出现 黑 白 黑
黑 黑 黑
这种情况,所以我们考虑用并查集合并两个区间,每个点可以挂一个并查集,每次$O(n)$合并一下
时间复杂度$O(n^3+m*nlogn)$
Merge的时候小细节:并查集数组开4倍 用
$1 \cdots n$表示上方
$n+1 \cdots 2n$表示下方
$1 \cdots n$表示上方
$2n+1 \cdots 4n$表示右边上下方
爆搞一下
(但是依然钟情于LCT的我是不会写线段树套并查集的w
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; struct node { int b, w, f[808]; void init (int n) { b = w = 0; for (int i = 0; i <= n; i++) f[i] = i; } int find (int x) { if (f[x] == x) return x; return f[x] = find(f[x]); } void merge (int a, int b) { f[find(a)] = find(b); } }; int n, m; bool map[205][205]; struct SegmentTree { node T[808]; #define LChild p<<1,l,mid #define RChild p<<1|1,mid+1,r void maintain (int p, int l, int r) { int lc = p<<1, rc = lc|1, mid = (l+r)/2; T[p].init(n<<2); T[p].b = T[lc].b + T[rc].b; T[p].w = T[lc].w + T[rc].w; for (int i = 1; i <= n; i++) T[p].f[i] = T[lc].f[i], T[p].f[i+n] = T[lc].f[i+n], T[p].f[i+n+n] = T[rc].f[i]+n*2, T[p].f[i+n+n+n] = T[rc].f[i+n]+n*2; for (int i = 1; i <= n; i++) if (map[mid][i]==map[mid+1][i]) { int f1 = T[p].find(i+n); int f2 = T[p].find(i+n+n); if (f1 != f2) { T[p].w -= (map[mid][i]==0), T[p].b -= (map[mid][i]==1); T[p].merge(f1,f2); } } for (int i = 1; i <= n; i++) { int fi = T[p].find(i); if (fi > n) T[p].f[fi] = T[p].f[i] = i; } for (int i = n*3+1; i <= n*4; i++) { int fi = T[p].find(i); if (fi <= n) T[p].f[i-n*2] = T[p].f[i]; else T[p].f[fi] = T[p].f[i-n*2] = i-n*2; } } void make (int r, int p) { T[p].init(n<<2); for (int i = 1; i <= n; i++) T[p].merge(i,i+n); for (int i = 2; i <= n; i++) if (map[r][i]==map[r][i-1]) { T[p].merge(i,i-1); T[p].merge(i+n,i+n-1); } for (int i = 1; i <= n; i++) if (T[p].f[i] == i) T[p].w += map[r][i]==0, T[p].b += map[r][i]==1; for (int i = 1; i <= n; i++) if (T[p].f[i+n] == i+n) T[p].w += map[r][i]==0, T[p].b += map[r][i]==1; } void build (int p, int l, int r) { if (l == r) make(r,p); else { int mid = (l+r)/2; build(LChild); build(RChild); maintain(p,l,r); } } void change (int p, int l, int r, int pos) { if (l == r) {make(r,p);return;} int mid = (l+r)/2; if (pos <= mid) change(LChild,pos); else change(RChild,pos); maintain(p,l,r); } void change (int x, int y) { map[x][y] = !map[x][y]; change (1, 1, n, x); } void query () { printf ("%d %d\n", T[1].b, T[1].w); } }Solve; int main () { scanf ("%d", &n); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) scanf ("%d", map[i]+j); Solve.build(1,1,n); scanf ("%d", &m); for (int i = 1; i <= m; i++) { int x, y; scanf ("%d %d", &x, &y); Solve.change(x,y); Solve.query(); } return 0; }
#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]); } }