zoukankan      html  css  js  c++  java
  • 洛谷P4121 [WC2005]双面棋盘(线段树套并查集)

    传送门

    先膜一下大佬->这里

    据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解

    我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举

    每一行内用并查集暴力枚举连通块这个应该容易理解,就是如果是同一个同色连通块的就用并查集连起来。那么怎么处理行与行之间的连通块嘞?

    因为几行连起来可以看做一块,那么我们用$[1,n]$维护最上面一行的连通性,用$[n+1,n*2]$维护最下面一行的连通性,然后用$[n*2+1,n*4]$作为辅助

    这一部分的细节还是看代码好了,写在注解里了

      1 //minamoto
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<algorithm>
      6 using namespace std;
      7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
      8 char buf[1<<21],*p1=buf,*p2=buf;
      9 inline int read(){
     10     #define num ch-'0'
     11     char ch;bool flag=0;int res;
     12     while(!isdigit(ch=getc()))
     13     (ch=='-')&&(flag=true);
     14     for(res=num;isdigit(ch=getc());res=res*10+num);
     15     (flag)&&(res=-res);
     16     #undef num
     17     return res;
     18 }
     19 const int N=505;
     20 int n,m;
     21 int chess[N][N],mp[N<<2];
     22 struct node{
     23     int fa[N<<2];
     24     inline void init(){for(int i=1;i<=(n<<2);++i) fa[i]=i;}
     25     int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
     26     inline void unique(int x,int y){fa[find(x)]=find(y);}
     27     inline bool check(int x,int y){return find(x)==find(y);}
     28 }data[N<<2];
     29 int wh[N],bl[N],L[N],R[N];
     30 void pushup(int p){
     31     int mid=L[p]+R[p]>>1;
     32     wh[p]=wh[p<<1]+wh[p<<1|1];
     33     bl[p]=bl[p<<1]+bl[p<<1|1];
     34     data[p].init();
     35     for(int i=1;i<=(n<<1);++i){
     36         data[p].unique(i,data[p<<1].find(i));
     37         //1~n记录左儿子最上面一行连通性
     38         //n+1~n*2记录左儿子最下面一行的连通性 
     39         data[p].unique(i+(n<<1),data[p<<1|1].find(i)+(n<<1));
     40         //n*2+1~n*3记录右儿子最上面一行连通性
     41         //n*3+1~n*4记录左儿子最下面一行的连通性 
     42     }
     43     //枚举左右儿子交界处是否有新的连通块 
     44     for(int i=1;i<=n;++i)
     45     if(chess[mid][i]==chess[mid+1][i]){
     46         if(data[p].check(i+n,i+(n<<1))) continue;
     47         data[p].unique(i+n,i+(n<<1));
     48         wh[p]-=chess[mid][i]^1;
     49         bl[p]-=chess[mid][i];
     50     }
     51     //下面这一段就是把所有节点的父亲都赋值为下标最小的点 
     52     //顺便记录最上面一行和最下面一行的连通性 
     53     for(int i=1;i<=(n<<2);++i)
     54     data[p].find(i),mp[i]=0;
     55     for(int i=1;i<=n;++i)
     56     if(!mp[data[p].fa[i]])
     57     mp[data[p].fa[i]]=i,data[p].fa[i]=i;
     58     else data[p].fa[i]=mp[data[p].fa[i]];
     59     for(int i=n*3+1;i<=(n<<2);++i)
     60     if(!mp[data[p].fa[i]])
     61     mp[data[p].fa[i]]=i-(n<<1),data[p].fa[i]=i-(n<<1);
     62     else data[p].fa[i]=mp[data[p].fa[i]];
     63     for(int i=1;i<=n;++i) data[p].fa[i+n]=data[p].fa[i+n*3];//记录一下这一块最下面一行的连通性 
     64 }
     65 void build(int p,int l,int r){
     66     L[p]=l,R[p]=r;
     67     if(l==r){
     68         wh[p]=chess[l][1]^1;
     69         bl[p]=chess[l][1];
     70         data[p].init();
     71         data[p].unique(1+n,1);
     72         for(int i=2;i<=n;++i){
     73             data[p].unique(i+n,i);
     74             if(chess[l][i-1]==chess[l][i]) data[p].unique(i,i-1);
     75             else wh[p]+=chess[l][i]^1,bl[p]+=chess[l][i];
     76         }
     77         return;
     78     }
     79     int mid=l+r>>1;
     80     build(p<<1,l,mid),build(p<<1|1,mid+1,r);
     81     pushup(p);
     82 }
     83 void update(int x,int p){
     84     if(L[p]==R[p]){
     85         wh[p]=chess[x][1]^1;
     86         bl[p]=chess[x][1];
     87         data[p].init();
     88         data[p].unique(n+1,1);
     89         for(int i=2;i<=n;++i){
     90             data[p].unique(i+n,i);
     91             if(chess[x][i-1]==chess[x][i]) data[p].unique(i,i-1);
     92             else wh[p]+=chess[x][i]^1,bl[p]+=chess[x][i];
     93         }
     94         return;
     95     }
     96     int mid=L[p]+R[p]>>1;
     97     if(x<=mid) update(x,p<<1);
     98     else update(x,p<<1|1);
     99     pushup(p);
    100 }
    101 int main(){
    102     //freopen("testdata.in","r",stdin);
    103     n=read();
    104     for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)
    105     chess[i][j]=read();
    106     build(1,1,n);
    107     m=read();
    108     while(m--){
    109         int x=read(),y=read();
    110         chess[x][y]^=1;
    111         update(x,1);
    112         printf("%d %d
    ",bl[1],wh[1]);
    113     }
    114     return 0;
    115 }
  • 相关阅读:
    设置tableview的滚动范围--iOS开发系列---项目中成长的知识三
    把所有界面的状态栏字体颜色设置为白色--iOS开发系列---项目中成长的知识一
    iOS开发遇到的坑之四--图片命名不规范
    使用Xcode连接开源中国
    iOS使用技巧---高效使用你的xcode
    修改mysql密码出现报错:ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corres
    ubuntu 18.04 为 mysql 设置 root 初始密码
    sudo: netstat:找不到命令的解决办法
    xpath中的ends-with无效解决方案
    python用selenium获取元素标签内容和属性值
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9600918.html
Copyright © 2011-2022 走看看