博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P4121 [WC2005]双面棋盘(线段树套并查集)
阅读量:6230 次
发布时间:2019-06-21

本文共 3948 字,大约阅读时间需要 13 分钟。

 

先膜一下大佬->

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

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

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

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

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

1 //minamoto  2 #include
3 #include
4 #include
5 #include
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\n",bl[1],wh[1]);113 }114 return 0;115 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9600918.html

你可能感兴趣的文章
Flutter之可滑动Widget
查看>>
富文本编辑器-CKeditor5
查看>>
前端基础22:数组迭代基本方法
查看>>
GGally与pairs相关关系图_史上最全(一)
查看>>
从内存映射mmap说开去
查看>>
Swift4如何扫描二维码了解一下
查看>>
散列表:如何实现word编辑器的拼写检查?
查看>>
可用的哈希函数(一)
查看>>
js关于数组常用函数
查看>>
Swift 项目总结 02 常用分类方法
查看>>
字符串&Math&Date
查看>>
复习webpack4之环境变量
查看>>
Linux - IO
查看>>
给大家整理了19个pythonic的编程习惯
查看>>
JVM之内存回收算法
查看>>
阿里高管告诉你 一个小猿如何更快的成长?
查看>>
多线程基础之synchronized和volatile
查看>>
52ABP前端升级2.0.x指南
查看>>
vue中组件之间的通信
查看>>
四大主场外交将展现中国会展新气象
查看>>