传送门

先膜一下大佬->这里

据说这题正解是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]双面棋盘(线段树套并查集)的更多相关文章

  1. P4121 [WC2005]双面棋盘

    题目 P4121 [WC2005]双面棋盘 貌似是刘汝佳出的题目?? 做法 线段树维护并查集 线段树分治\(1\)~\(n\)行,我们要考虑维护的肯定是黑.白各自的联通块数量 考虑区间合并,其实就与中 ...

  2. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

  3. 洛谷P2661 信息传递(最小环,并查集)

    洛谷P2661 信息传递 最小环求解采用并查集求最小环. 只适用于本题的情况.对于新加可以使得两个子树合并的边,总有其中一点为其中一棵子树的根. 复杂度 \(O(n)\) . #include< ...

  4. Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)

    题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...

  5. BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...

  6. 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)

    传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...

  7. 【BZOJ2733】永无乡(线段树,并查集)

    [BZOJ2733]永无乡(线段树,并查集) 题面 BZOJ 题解 线段树合并 线段树合并是一个很有趣的姿势 前置技能:动态开点线段树 具体实现:每次合并两棵线段树的时候,假设叫做\(t1,t2\), ...

  8. 2019牛客暑期多校训练营(第八场)E:Explorer(LCT裸题 也可用线段树模拟并查集维护连通性)

    题意:给定N,M,然后给出M组信息(u,v,l,r),表示u到v有[l,r]范围的通行证有效.问有多少种通行证可以使得1和N连通. 思路:和bzoj魔法森林有点像,LCT维护最小生成树.  开始和队友 ...

  9. 线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)

    闲话 stO猫锟学长,满脑子神仙DS 网上有不少Dalao把线段树分治也归入CDQ分治? 还是听听YCB巨佬的介绍: 狭义:只计算左边对右边的贡献. 广义:只计算外部对内部的贡献. 看来可以理解为广义 ...

随机推荐

  1. hdu--2111--Saving HDU(贪心)

    #include<iostream> #include<vector> #include<algorithm> using namespace std; struc ...

  2. codeforces 515C C. Drazil and Factorial(水题,贪心)

    题目链接: C. Drazil and Factorial time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  3. 如果你使用WebView+FloatingActionButton

    在WebView中想要使用FAB,如果你想向上滑动的时候隐藏FAB,那么需要再WebView外面套一个ScrollView! 原因之前也分析过,和为什么ListView不能让ToolBar.Tab隐藏 ...

  4. 基于Ubuntu交叉编译FFmpeg Windows SDK

    写在前面 FFmpeg是一个开源且跨平台的音视频解决方案,集采集.转码.流式化为一身,项目的libavcodec编解码模块和libavformat媒体格式模块,支持非常非常丰富的编解码格式和容器封装格 ...

  5. dubbo monitor simple 监控原理分析

    监控机制: 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心.监控中心负责统计各服务调用次数,调用时间等. 监控元数据存储目录结构: --dubbo.jetty ...

  6. WC2010 BZOJ1758 重建计划_长链剖分

    题目大意: 求长度$\in [L,U]$的路径的最大边权和平均值. 题解 首先二分就不用说了,分数规划大家都懂. 这题有非常显然的点分治做法,但还是借着这个题学一波长链剖分. 其长链剖分本身也没啥,就 ...

  7. 省选/NOI刷题Day1

    bzoj4864 Splay乱搞 bzoj3669 正解LCT,考虑上下界的spfa可过 bzoj3668 位运算 暴力 bzoj3670 KMP DP bzoj3671 含有最小的一个数的路径一定比 ...

  8. URAL1517Freedom of Choice(后缀数组)

    Background Before Albanian people could bear with the freedom of speech (this story is fully describ ...

  9. Linux不停往外发包

    一台Linux这两天不停往外发包,造成外部无法访问. [root@ct-nat ~]# watch ifconfig-------------查看数据包新增情况 Every 2.0s: ifconfi ...

  10. netty中的引导Bootstrap客户端

    一.Bootstrap Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化.下面我以 Netty 源码例子中的 E ...