洛谷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巨佬的介绍: 狭义:只计算左边对右边的贡献. 广义:只计算外部对内部的贡献. 看来可以理解为广义 ...
随机推荐
- uva 111 History Grading(lcs)
题目描述 在信息科学中有一些是关于在某些条件限制下,找出一些计算的最大值. 以历史考试来说好了,学生被要求对一些历史事件根据其发生的年代顺序来排列.所有事件顺序都正确的学生无疑的可以得满分.但是那些没 ...
- django admin扩展user表password验证及set_password
一般如果扩展了django user内置表,在admin后台创建新用户的时候密码将会变成明文,故而导致登录不成功.所以我们在admin.py可以通过form自定义进行对password进行操作,可以双 ...
- 关于phonegap的cookie
angular搞了一半现在开始搞phonegap(确切的说应该叫cordova). 因为有很紧迫的需求,所以我也不能系统的学,只能遇到啥问题就解决啥.第一个问题就是cookie. 经过调研,cordo ...
- python 链接sharepoint 2013 REST api
import requests,simplejson from requests_ntlm import HttpNtlmAuth p1 = requests.get("http://you ...
- L100
The world’s lightest wireless flying machine lifts off1Circult: cutting the circuitry from copper fo ...
- docker 安装与常用命令与常用容器(containers)环境
注意区别 container 与 image 的关系,container 的建立需要 image 的承载,也即 container 依赖 image,停止并删除了 container 并不会删除 im ...
- PS色调— —通道混合
clc; clear all; close all; addpath('E:\PhotoShop Algortihm\Image Processing\PS Algorithm'); Image=im ...
- BZOJ1218:[HNOI2003]激光炸弹
我对状态空间的理解:https://www.cnblogs.com/AKMer/p/9622590.html 题目传送门:https://www.lydsy.com/JudgeOnline/probl ...
- LVS实战1
(一).NAT模式:NAT模型:地址转换类型,主要是做地址转换,类似于iptables的DNAT类型,它通过多目标地址转换,来实现负载均衡:特点和要求: 1.LVS(Director)上面需要双网卡: ...
- 二 kafka设计原理
kafka的设计初衷是希望作为一个统一的信息收集平台,能够实时的收集反馈信息,并需要能够支撑较大的数据量,且具备良好的容错能力. 1.持久性 kafka使用文件存储消息,这就直接决定kafka ...