洛谷P4121 [WC2005]双面棋盘(线段树套并查集)
先膜一下大佬->这里
据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解
我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举
每一行内用并查集暴力枚举连通块这个应该容易理解,就是如果是同一个同色连通块的就用并查集连起来。那么怎么处理行与行之间的连通块嘞?
因为几行连起来可以看做一块,那么我们用$[1,n]$维护最上面一行的连通性,用$[n+1,n*2]$维护最下面一行的连通性,然后用$[n*2+1,n*4]$作为辅助
这一部分的细节还是看代码好了,写在注解里了
//minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
const int N=;
int n,m;
int chess[N][N],mp[N<<];
struct node{
int fa[N<<];
inline void init(){for(int i=;i<=(n<<);++i) fa[i]=i;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void unique(int x,int y){fa[find(x)]=find(y);}
inline bool check(int x,int y){return find(x)==find(y);}
}data[N<<];
int wh[N],bl[N],L[N],R[N];
void pushup(int p){
int mid=L[p]+R[p]>>;
wh[p]=wh[p<<]+wh[p<<|];
bl[p]=bl[p<<]+bl[p<<|];
data[p].init();
for(int i=;i<=(n<<);++i){
data[p].unique(i,data[p<<].find(i));
//1~n记录左儿子最上面一行连通性
//n+1~n*2记录左儿子最下面一行的连通性
data[p].unique(i+(n<<),data[p<<|].find(i)+(n<<));
//n*2+1~n*3记录右儿子最上面一行连通性
//n*3+1~n*4记录左儿子最下面一行的连通性
}
//枚举左右儿子交界处是否有新的连通块
for(int i=;i<=n;++i)
if(chess[mid][i]==chess[mid+][i]){
if(data[p].check(i+n,i+(n<<))) continue;
data[p].unique(i+n,i+(n<<));
wh[p]-=chess[mid][i]^;
bl[p]-=chess[mid][i];
}
//下面这一段就是把所有节点的父亲都赋值为下标最小的点
//顺便记录最上面一行和最下面一行的连通性
for(int i=;i<=(n<<);++i)
data[p].find(i),mp[i]=;
for(int i=;i<=n;++i)
if(!mp[data[p].fa[i]])
mp[data[p].fa[i]]=i,data[p].fa[i]=i;
else data[p].fa[i]=mp[data[p].fa[i]];
for(int i=n*+;i<=(n<<);++i)
if(!mp[data[p].fa[i]])
mp[data[p].fa[i]]=i-(n<<),data[p].fa[i]=i-(n<<);
else data[p].fa[i]=mp[data[p].fa[i]];
for(int i=;i<=n;++i) data[p].fa[i+n]=data[p].fa[i+n*];//记录一下这一块最下面一行的连通性
}
void build(int p,int l,int r){
L[p]=l,R[p]=r;
if(l==r){
wh[p]=chess[l][]^;
bl[p]=chess[l][];
data[p].init();
data[p].unique(+n,);
for(int i=;i<=n;++i){
data[p].unique(i+n,i);
if(chess[l][i-]==chess[l][i]) data[p].unique(i,i-);
else wh[p]+=chess[l][i]^,bl[p]+=chess[l][i];
}
return;
}
int mid=l+r>>;
build(p<<,l,mid),build(p<<|,mid+,r);
pushup(p);
}
void update(int x,int p){
if(L[p]==R[p]){
wh[p]=chess[x][]^;
bl[p]=chess[x][];
data[p].init();
data[p].unique(n+,);
for(int i=;i<=n;++i){
data[p].unique(i+n,i);
if(chess[x][i-]==chess[x][i]) data[p].unique(i,i-);
else wh[p]+=chess[x][i]^,bl[p]+=chess[x][i];
}
return;
}
int mid=L[p]+R[p]>>;
if(x<=mid) update(x,p<<);
else update(x,p<<|);
pushup(p);
}
int main(){
//freopen("testdata.in","r",stdin);
n=read();
for(int i=;i<=n;++i) for(int j=;j<=n;++j)
chess[i][j]=read();
build(,,n);
m=read();
while(m--){
int x=read(),y=read();
chess[x][y]^=;
update(x,);
printf("%d %d\n",bl[],wh[]);
}
return ;
}
洛谷P4121 [WC2005]双面棋盘(线段树套并查集)的更多相关文章
- P4121 [WC2005]双面棋盘
题目 P4121 [WC2005]双面棋盘 貌似是刘汝佳出的题目?? 做法 线段树维护并查集 线段树分治\(1\)~\(n\)行,我们要考虑维护的肯定是黑.白各自的联通块数量 考虑区间合并,其实就与中 ...
- 洛谷 P3373 【模板】线段树 2
洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...
- 洛谷P2661 信息传递(最小环,并查集)
洛谷P2661 信息传递 最小环求解采用并查集求最小环. 只适用于本题的情况.对于新加可以使得两个子树合并的边,总有其中一点为其中一棵子树的根. 复杂度 \(O(n)\) . #include< ...
- Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)
题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...
- BZOJ4399魔法少女LJJ——线段树合并+并查集
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...
- 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)
传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...
- 【BZOJ2733】永无乡(线段树,并查集)
[BZOJ2733]永无乡(线段树,并查集) 题面 BZOJ 题解 线段树合并 线段树合并是一个很有趣的姿势 前置技能:动态开点线段树 具体实现:每次合并两棵线段树的时候,假设叫做\(t1,t2\), ...
- 2019牛客暑期多校训练营(第八场)E:Explorer(LCT裸题 也可用线段树模拟并查集维护连通性)
题意:给定N,M,然后给出M组信息(u,v,l,r),表示u到v有[l,r]范围的通行证有效.问有多少种通行证可以使得1和N连通. 思路:和bzoj魔法森林有点像,LCT维护最小生成树. 开始和队友 ...
- 线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)
闲话 stO猫锟学长,满脑子神仙DS 网上有不少Dalao把线段树分治也归入CDQ分治? 还是听听YCB巨佬的介绍: 狭义:只计算左边对右边的贡献. 广义:只计算外部对内部的贡献. 看来可以理解为广义 ...
随机推荐
- Android 之 Matrix(转)
原文:http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#code Android Matrix Matrix的数学原理 平 ...
- 初次接触Servlet3.0
Servlet3.0 一.要求 MyEclipes10.0或以上版本! 发布到Tomcat7.0或以上版本!二.步骤 创建JavaEE6.0应用 --------------------------- ...
- hdu5606 tree (并查集)
tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submis ...
- STL stl_uninitialized.h
stl_uninitialized.h // Filename: stl_uninitialized.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com ...
- Android的五大基本组件
Android的基本组件 1.Activity Activity 是最基本的模块,一般称之为“活动”,在应用程序中一般一个Activity就是一个单独的屏幕.每一个活动都被实现为一个独立的类,并且从活 ...
- 跨平台的WebRTC客户端框架:OpenWebRTC
Webrtc的ios框架编译 http://www.th7.cn/Program/IOS/201502/390418.shtml WebRTC in WebKit : http://www.webrt ...
- bzoj 4501: 旅行 01分数规划+概率期望dp
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=4501 题解: 首先我们不考虑可以删除边的情况下,如何计算期望边数. 然后我们发现这是个有 ...
- MySQL 和 InnoDB
发现一篇总结的很不错的文章,转一下 (原文作者:Draveness 原文链接:https://draveness.me/mysql-innodb) 作为一名开发人员,在日常的工作中会难以避免地接触 ...
- bzoj 3994 约数个数和 —— 反演+数论分块
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3994 推导过程和这里一样:https://www.cnblogs.com/MashiroSk ...
- 文件上传框的美化+预览+ajax
1.文件上传基本写法: <input type="file" name="" id="" value="" /&g ...