[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 ...
随机推荐
- 微信开发 提示 Redirect_uri(错误10003)
情景: 搭建完成一个网站,使用微信打开链接地址,结果报错1003 完整的错误信息: 出现这种情况一般有两种原因: 1.没有配置网页授权 我们可以根据微信的开发者文档http://mp.weixin. ...
- JavaScript生成二维码图片
1.引入一个二维码工具的js文件,同时需要引入jquery文件 下面是jquery.qrcode.min.js文件内容: (function(r){r.fn.qrcode=function(h){va ...
- C\C++学习笔记 1
C++记录1 C的头文件为math.h C++的为 cmath using编译指令 namespace 区分不同产品的函数.Mics::cout Linux::cout cout << 即 ...
- vue2.0生命周期
https://www.cnblogs.com/goloving/p/8616989.html(copy )
- 用Canvas实现一些简单的图片滤镜
1.灰度滤镜 对于灰度滤镜的实现一般有三种算法 1) 最大值法:即新的颜色值R=G=B=Max(R,G,B),通过这种方法处理后的图片看起来亮度值偏高. 2) 平均值法:即新的颜色值R=G=B=(R+ ...
- 如何抓取电商的数据 & Python
如何抓取电商的数据 & Python https://www.zhihu.com/question/40720286 https://www.zhihu.com/question/382455 ...
- python设计模式第二十天【迭代器模式】
1.不使用迭代器出现的问题 (1)容器承担了太多的功能,一方面提供添加和删除等功能,还需提供遍历访问功能 (2)在容器访问遍历过程中,需要保存遍历状态,当和元素的添加和删除混杂在一起时,容易引起混乱 ...
- 洛谷 p1219 八皇后
刚参加完蓝桥杯 弱鸡错了好几道..回头一看确实不难 写起来还是挺慢的 于是开始了刷题的道路 蓝桥杯又名搜索杯 暴力杯...于是先从dfs刷起 八皇后是很经典的dfs问题 洛谷的这道题是这样的 上面的布 ...
- 解决post、get端中文乱码问题
在web.xml中配置: <filter> <filter-name>CharacterEncodingFilter</filter-name> <filte ...
- C# 23种设计模式汇总
创建型模式工厂方法(Factory Method)在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节.工厂方法模式的核心是一个抽象工厂类,各种具体工 ...