[WC2005]双面棋盘

description

洛谷
给出一个\(n\times n\)的黑白棋盘。
\(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数。

data range

\[n\le 200,m\le 10000 \]

solution

解决动态维护图连通性的方法有2种:
一种是通过\(LCT\)动态维护最大删边时间生成树,另一种是线段树分治。

所以当然线段树分治更好写不是吗反正不会LCT的做法

然后稍稍讨论一波就完了

Code

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define F "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const int N=2e2+10;
const int K=4e4+10;
const int mod=998244353;
const int inf=2147483647;
const ll INF=1ll<<60;
const dd eps=1e-7;
const dd pi=acos(-1);
il ll read(){
  RG ll data=0,w=1;RG char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  if(ch=='-')w=-1,ch=getchar();
  while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
  return data*w;
}

il void file(){
  freopen(F".in","r",stdin);
  freopen(F".out","w",stdout);
}

int n,m,p[N][N],cnt,c[N][N],v[N][N],b,w;VI a[N][N];bool vis[N][N];
struct node{int x,y,c;}now;
vector<node>M[K];
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
void modify(int i,int l,int r,int x,int y){
  if(x<=l&&r<=y){M[i].push_back(now);return;}
  if(x<=mid)modify(ls,l,mid,x,y);
  if(mid<y)modify(rs,mid+1,r,x,y);
}

int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
struct Mod{int id,u,v;};vector<Mod>cal;
int nowid,top;
int fa[K];
int find(int x){
  if(!fa[x])return x;
  RG int ff=find(fa[x]);
  if(fa[x]!=ff){cal.push_back((Mod){nowid,x,fa[x]});top++;}
  return fa[x]=ff;
}
il void merge(int x,int y){
  x=find(x);y=find(y);if(x==y)return;
  cal.push_back((Mod){nowid,x,fa[x]});top++;
  fa[x]=y;
}

#define pd(i,j) (i<1||i>n||j<1||j>n||!vis[i][j])
set<int>S;
il void insert(int x,int y,int col){
  vis[x][y]=1;c[x][y]=col;nowid=p[x][y];
  S.clear();
  for(RG int k=0,xx,yy;k<4;k++){
    xx=x+dx[k];yy=y+dy[k];if(pd(xx,yy))continue;
    if(c[xx][yy]==c[x][y]){
      S.insert(find(p[xx][yy]));
      merge(p[x][y],p[xx][yy]);
    }
  }
  v[x][y]=1-S.size();col?b+=v[x][y]:w+=v[x][y];
}

il void undo(int x,int y){
  nowid=p[x][y];
  while(top&&cal[top-1].id==nowid)
    fa[cal[top-1].u]=cal[top-1].v,cal.pop_back(),top--;
  c[x][y]?b-=v[x][y]:w-=v[x][y];vis[x][y]=0;
}

void divide(int i,int l,int r){
  RG int sz=M[i].size();
  for(RG int k=0;k<sz;k++)
    insert(M[i][k].x,M[i][k].y,M[i][k].c);
  if(l==r)printf("%d %d\n",b,w);
  else{divide(ls,l,mid);divide(rs,mid+1,r);}
  for(RG int k=sz-1;~k;k--)
    undo(M[i][k].x,M[i][k].y);
}

int main()
{
  n=read();
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=n;j++)
      {p[i][j]=++cnt;c[i][j]=read()^1;a[i][j].push_back(1);}
  m=read();
  for(RG int i=1,x,y;i<=m;i++){
    x=read();y=read();a[x][y].push_back(i);
  }
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=n;j++)
      a[i][j].push_back(m+1);
  for(RG int i=1;i<=n;i++)
    for(RG int j=1;j<=n;j++)
      for(RG int k=0,sz=a[i][j].size();k<sz-1;k++){
	c[i][j]^=1;now=(node){i,j,c[i][j]};
	if(a[i][j][k]!=a[i][j][k+1])
	  modify(1,1,m,a[i][j][k],a[i][j][k+1]-1);
      }
  divide(1,1,m);
  return 0;
}

posted @ 2018-10-15 20:32  cjfdf  阅读(208)  评论(0编辑  收藏  举报