Description
Description

Input
Input

Output
Output

Sample Input
Sample Input

Sample Output
Sample Output

HINT
HINT

Source
鸣谢刘汝佳先生授权使用

思路
线段树,树上的节点[left,right]表示[left,right]这些行,线段树存黑色区域的个数、白色区域的个数,以及左边界和右边界的情况。在合并时只要暴力枚举两区间的交接处,如果是同一种颜色而且不在同一并查集内,就将这两种颜色合并,同时相应的颜色个数减一。

代码

#include <cstdio>

const int maxn=500;

int map[maxn+10][maxn+10],n;
int tmp[(maxn<<2)+10];

struct data
{
  int fa[(maxn<<2)+10],b,w,tot,left,right;

  int find(int x)
  {
    if(fa[x]==x)
      {
        return x;
      }
    else
      {
        return fa[x]=find(fa[x]);
      }
  }

  int init(int x)
  {
    b=w=0;
    left=right=x;
    for(register int i=1; i<=n; ++i)
      {
        fa[i]=i;
      }
    for(register int i=1; i<=n; ++i)
      {
        if((i==1)||(map[x][i-1]!=map[x][i]))
          {
            if(map[x][i])
              {
                ++b;
              }
            else
              {
                ++w;
              }
          }
        else
          {
            fa[find(i)]=fa[find(i-1)];
          }
      }
    for(register int i=1; i<=n; ++i)
      {
        fa[i+n]=fa[i];
      }
    return 0;
  }

  data operator +(data other)//合并两个区间
  {
    data res;
    res.left=left;
    res.right=other.right;
    int mid=(res.left+res.right)>>1;
    res.b=b+other.b;
    res.w=w+other.w;
    for(register int i=1; i<=n<<1; ++i)
      {
        res.fa[i]=fa[i];
      }
    for(register int i=1; i<=n<<1; ++i)
      {
        res.fa[i+(n<<1)]=other.fa[i]+(n<<1);
      }
    for(register int i=1; i<=n; ++i)
      {
        if(map[mid][i]==map[mid+1][i])
          {
            int x=res.find(i+n),y=res.find(i+(n<<1));
            if(x!=y)
              {
                if(map[mid][i])
                  {
                    --res.b;
                  }
                else
                  {
                    --res.w;
                  }
                res.fa[x]=y;
              }
          }
      }
    for(register int i=1; i<=n<<2; ++i)
      {
        if(i<=n)
          {
            tmp[res.find(i)]=i;
          }
        if(i>n*3)
          {
            tmp[res.find(i)]=i-(n<<1);
          }
      }
    for(register int i=1; i<=n; ++i)
      {
        res.fa[i]=tmp[res.fa[i]];
        res.fa[i+n]=tmp[res.fa[i+n*3]];
      }
    return res;
  }
};
struct segment_tree
{
  data val[maxn+10];

  int build(int now,int left,int right)
  {
    if(left==right)
      {
        val[now].init(left);
        return 0;
      }
    int mid=(left+right)>>1;
    build(now<<1,left,mid);
    build(now<<1|1,mid+1,right);
    val[now]=val[now<<1]+val[now<<1|1];
    return 0;
  }

  int modify(int now,int left,int right,int pos)
  {
    if(left==right)
      {
        val[now].init(left);
        return 0;
      }
    int mid=(left+right)>>1;
    if(pos<=mid)
      {
        modify(now<<1,left,mid,pos);
      }
    else
      {
        modify(now<<1|1,mid+1,right,pos);
      }
    val[now]=val[now<<1]+val[now<<1|1];
    return 0;
  }
};

segment_tree st;
int m,a,b;

inline int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

int main()
{
  n=read();
  for(register int i=1; i<=n; ++i)
    {
      for(register int j=1; j<=n; ++j)
        {
          map[i][j]=read();
        }
    }
  st.build(1,1,n);
  m=read();
  while(m--)
    {
      a=read();
      b=read();
      map[a][b]=1-map[a][b];
      st.modify(1,1,n,a);
      printf("%d %d\n",st.val[1].b,st.val[1].w);
    }
  return 0;
}