[WC2005]双面棋盘(并查集+分治)
题目描述
题解
唉,还是码力不行,写了一个多小时发现想错了又重构了一个多小时。
这道题意图很显然,动态维护联通块,有一个经典做法就是用LCT维护按照删除时间维护的最大生成树。
网上还有一种神奇的做法,线段树套并查集,蒟蒻表示不懂。。
这道题可以利用并查集操作可以撤销这种性质来做。
线段树分治
线段树分治可以分两种情况,操作之间独立和操作之间不独立。
操作之间独立意味着我先完成哪个操作就可以,例如找最优点,有一道例题。
还有一种是操作之间是可以相互影响的,比如说这道题,连通性这种东西和我加的每一条边都有关。
我们可以按时间分治,先离线找出每条边出现的时间段,把这些时间段加入线段树中,然后在线段树上dfs,进入节点时把所有边加入,删除时栈序撤销来的时候的操作(因为线段树dfs的过程也是压栈弹栈的过程,所以我们可以准确撤销操作),然后在根节点统计答案,联通块的个数为点数-边数,点数这种东西我们可以直接离线维护(我一开始傻了)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 40002
#define maxn 209
using namespace std;
int n,id[maxn][maxn],f[N],tot,ls[N<<],rs[N<<],b[N],bl,w[N],wl,deep[N],num,last[N<<],m,root,a[maxn][maxn],bian;
int tag[maxn][maxn][],anti[],color[N<<];
const int dx[]={,,-,};
const int dy[]={,,,-};
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
int find(int x){return f[x]==x?x:find(f[x]);}
struct node{int id,co;};
struct rbs{int dep,root,link,co;};
struct node2{int x,y;};
vector<node>vec[N<<];
vector<rbs>zh[N<<];
node2 linko[N<<];
void upd(int &cnt,int l,int r,int L,int R,int x,int y){
if(!cnt)cnt=++tot;
if(l>=L&&r<=R){vec[cnt].push_back(node{x,y});return;}
int mid=(l+r)>>;
if(mid>=L)upd(ls[cnt],l,mid,L,R,x,y);
if(mid<R)upd(rs[cnt],mid+,r,L,R,x,y);
}
void solve(int &cnt,int l,int r){
if(!cnt)cnt=++tot;
//cout<<l<<" **** "<<r<<endl;
for(int i=;i<vec[cnt].size();++i){
int id=vec[cnt][i].id,co=vec[cnt][i].co;
int x=linko[id].x,y=linko[id].y;
int xx=find(x),yy=find(y);
if(xx!=yy){
if(co)bl++;else wl++;
if(deep[xx]<deep[yy])swap(xx,yy);
zh[cnt].push_back(rbs{deep[xx],xx,yy,co});
f[yy]=xx;deep[xx]=max(deep[xx],deep[yy]+);
}
}
// cout<<b[l]<<" "<<w[l]<<" "<<bl<<" "<<wl<<endl;
if(l==r){if(l)printf("%d %d\n",b[l]-bl,w[l]-wl);}
else{
int mid=(l+r)>>;
solve(ls[cnt],l,mid);
solve(rs[cnt],mid+,r);
}
while(zh[cnt].size()){
rbs x=zh[cnt].back();zh[cnt].pop_back();
deep[x.root]=x.dep;f[x.link]=x.link;
if(x.co)bl--;else wl--;
}
}
int main(){
anti[]=;anti[]=;anti[]=;anti[]=;
n=rd();int x,y;
for(int i=;i<=n;++i)
for(int j=;j<=n;++j){
a[i][j]=rd(),id[i][j]=++num;
if(a[i][j])b[]++;else w[]++;
}
for(int i=;i<=num;++i)f[i]=i,deep[i]=;
memset(last,-,sizeof(last));
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
for(int k=;k<;++k){
int xx=i+dx[k],yy=j+dy[k];
if(!id[xx][yy])continue;
tag[i][j][k]=tag[xx][yy][anti[k]]=++bian;
if(a[i][j]==a[xx][yy])last[bian]=,color[bian]=a[i][j];
linko[bian]=node2{id[i][j],id[xx][yy]};
}
m=rd();
for(int i=;i<=m;++i){
x=rd();y=rd();b[i]=b[i-];w[i]=w[i-];
if(a[x][y])b[i]--,w[i]++;else b[i]++,w[i]--;
for(int k=;k<;++k){
int xx=x+dx[k],yy=y+dy[k],_id=tag[x][y][k];
if(!_id)continue;
if(a[x][y]==a[xx][yy])
upd(root,,m,last[_id],i-,_id,a[x][y]),last[_id]=-;
else last[_id]=i,color[_id]=a[xx][yy];
}
a[x][y]^=;
}
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
for(int k=;k<;++k){
int xx=i+dx[k],yy=j+dy[k],_id=tag[i][j][k];
if(~last[_id])upd(root,,m,last[_id],m,_id,color[_id]);
}
solve(root,,m);
return ;
}
[WC2005]双面棋盘(并查集+分治)的更多相关文章
- P4121 [WC2005]双面棋盘
题目 P4121 [WC2005]双面棋盘 貌似是刘汝佳出的题目?? 做法 线段树维护并查集 线段树分治\(1\)~\(n\)行,我们要考虑维护的肯定是黑.白各自的联通块数量 考虑区间合并,其实就与中 ...
- [WC2005]双面棋盘(线段树+并查集)
线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...
- 洛谷P4121 [WC2005]双面棋盘(线段树套并查集)
传送门 先膜一下大佬->这里 据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解 我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举 每一行内用并查集暴力枚举连通块这个应该容易理 ...
- 【题解】Luogu P4121 [WC2005]双面棋盘
原题传送门 这道题肥肠毒瘤qwqwq,我被卡了qwqwq 这题的正解好像是线段树+并查集,但由于我人丑常数大被卡成了70 #include <bits/stdc++.h> #define ...
- [WC2005]双面棋盘
description 洛谷 给出一个\(n\times n\)的黑白棋盘. \(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数. data range \[n\le 200, ...
- 线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)
闲话 stO猫锟学长,满脑子神仙DS 网上有不少Dalao把线段树分治也归入CDQ分治? 还是听听YCB巨佬的介绍: 狭义:只计算左边对右边的贡献. 广义:只计算外部对内部的贡献. 看来可以理解为广义 ...
- 2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树
目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)E_Explorer) 题意: 链接 题目类似:CF366D,Gym101652T 本题给你\(n(100000)\)个点\(m(1000 ...
- 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集
[BZOJ1453][Wc]Dface双面棋盘 Description Input Output Sample Input Sample Output HINT 题解:话说看到题的第一反应其实是LCT ...
- hdu_5354_Bipartite Graph(cdq分治+并查集判二分图)
题目链接:hdu_5354_Bipartite Graph 题意: 给你一个由无向边连接的图,问对于每一个点来说,如果删除这个点,剩下的点能不能构成一个二分图. 题解: 如果每次排除一个点然后去DFS ...
随机推荐
- jdk环境变量配置注意事项
cmd 运行java -version 显示错误 Registry key 'Software\JavaSoft\Java Runtime Environment\CurrentVersion'has ...
- 【Python3练习题 005】输入三个整数x,y,z,请把这三个数由小到大输出
import re x, y, z = re.split(',| |,| ', input('请输入3个数字,用逗号或空格隔开:'))x, y, z = int(x), int(y), int(z) ...
- Thread(生产者和消费者) wait、notify、notifyAll
在java中,线程间的通信可以使用wait.notify.notifyAll来进行控制.从名字就可以看出来这3个方法都是跟多线程相关的,但是可能让你感到吃惊的是:这3个方法并不是Thread类或者是R ...
- Oracle创建及调用存储过程
- Eclipse的DEgub调试乱跳
去掉勾选,是软件的BUG
- SSM框架整合系列——第一步
环境: JDK8 idea2018.2 maven3.5 spring和springMVC是天然集成,所以只需要解决mybatis和spring的整合问题,重点整合mybatis和spring的两个东 ...
- PHP关联查询
article文章表: aid title content uid 1 文章1 文章1正文内容... 1 2 文章2 文章2正文内容... 1 3 文章3 文章3正文内容... 2 4 文章4 文章4 ...
- 转载 -- jquery easyui datagrid 动态表头 + 嵌套对象属性展示
代码功能: 1.datagrid 的表头由后台生成,可以配置在数据库 2.datagrid 的列绑定数据 支撑嵌套对象 $(function() { var columns = new Array() ...
- Python——Django-应用的models.py内容
一.数据的相关配置 #数据库的相关配置 DATABASE = { 'default':{ #连接的数据库类型 'ENGINE':'django.db.backends.sqlite3', #连接数据库 ...
- Linux下 rewrite_mod 的配置
以下使用最新的 Ubuntu 16.04 测试; 安装好apache后先确认有没有rewrite模块,大多数情况下是有的:ls /etc/apache2/mods-available |grep re ...