传送门

先膜一下大佬->这里

据说这题正解是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. vue-mixins使用注意事项和高级用法

    因为在项目中 mixins(混合)特性使用频率是很高的 有必要熟练掌握官方文档: mixins 实际项目中 一般都存在 列表(list) 这种很常见的使用场景 话再多都不如上demo file: mi ...

  2. 使用CSS3制作酷炫防苹果复选框 自行测试!

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Tomcat_总结_02_单机多实例

    一.tomcat下载及环境变量配置 1.tomcat下载 下载地址:tomcat官网 2.环境变量配置 只用配置一个CATALINA_HOME就可以了 二.CATALINA_HOME 与 CATALI ...

  4. C++ 值传递、址传递、引用传递

    一.值传递   int func(int p) 值传递会在栈中开辟一块空间 p,使得p和实参的a 同值. 此时你在函数func里面对p进行任何操作都不会对原值a产生任何影响.因为a 和p本就就是两个变 ...

  5. PostgreSQL正则及模糊查询优化

    1.带前缀的模糊查询  ~'^abc' 可以使用btree索引优化 create index idx_info on table_name(info) 2.带后缀的模糊查询  ~'abc$' 可以使用 ...

  6. linux导出Mysql数据sql脚本

  7. POJ2406Power Strings (最小循环节)(KMP||后缀数组)

    Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc&quo ...

  8. bzoj 1242 弦图判定 MCS

    题目大意: 给定一张无向图,判断是不是弦图. 题解: 今天刚学了<弦图与区间图> 本来写了一个60行+的学习笔记 结果因为忘了保存重启电脑后被还原了... 那就算了吧. MCS最大势算法, ...

  9. bzoj 2300: [HAOI2011]防线修建 凸包

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2300 题解 这道题让我们维护一个支持动态删除点的上凸壳 并且告诉了我们三个一定不会被删除 ...

  10. 使用tftp给ARM下载程序

    使用tftp给ARM下载程序 1.开发板和主机能够ping的通 前提:要把计算机的防火墙关了,不然就会出现下面这种情况 如果电脑连接的无线网,那么设置本地连接的ip设置为固定ip.Ip地址和开发的ip ...