题目描述

题解

唉,还是码力不行,写了一个多小时发现想错了又重构了一个多小时。

这道题意图很显然,动态维护联通块,有一个经典做法就是用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]双面棋盘(并查集+分治)的更多相关文章

  1. P4121 [WC2005]双面棋盘

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

  2. [WC2005]双面棋盘(线段树+并查集)

    线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...

  3. 洛谷P4121 [WC2005]双面棋盘(线段树套并查集)

    传送门 先膜一下大佬->这里 据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解 我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举 每一行内用并查集暴力枚举连通块这个应该容易理 ...

  4. 【题解】Luogu P4121 [WC2005]双面棋盘

    原题传送门 这道题肥肠毒瘤qwqwq,我被卡了qwqwq 这题的正解好像是线段树+并查集,但由于我人丑常数大被卡成了70 #include <bits/stdc++.h> #define ...

  5. [WC2005]双面棋盘

    description 洛谷 给出一个\(n\times n\)的黑白棋盘. \(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数. data range \[n\le 200, ...

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

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

  7. 2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树

    目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)E_Explorer) 题意: 链接 题目类似:CF366D,Gym101652T 本题给你\(n(100000)\)个点\(m(1000 ...

  8. 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集

    [BZOJ1453][Wc]Dface双面棋盘 Description Input Output Sample Input Sample Output HINT 题解:话说看到题的第一反应其实是LCT ...

  9. hdu_5354_Bipartite Graph(cdq分治+并查集判二分图)

    题目链接:hdu_5354_Bipartite Graph 题意: 给你一个由无向边连接的图,问对于每一个点来说,如果删除这个点,剩下的点能不能构成一个二分图. 题解: 如果每次排除一个点然后去DFS ...

随机推荐

  1. Azure系列2.1.7 —— BlobRequestOptions

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  2. Latex常用软件

    Linux texMaker sudo apt-get install texlive-full sudo apt-get install texmaker

  3. Oracle NVL空值处理函数

    --NVL空值处理函数 --需求:显示价格表中业主类型ID为1的价格记录 如果上限值为null,则显示9999999 ) from dual; select * from t_pricetable ) ...

  4. day 7-11 初识MySQL数据库及安装密码设置破解

    一. 什么是数据库 之前所学,数据要永久保存,比如用户注册的用户信息,都是保存于文件中,而文件只能存在于某一台机器上. 如果我们不考虑从文件中读取数据的效率问题,并且假设我们的程序所有的组件都运行在一 ...

  5. 如何使用apache自带的ab压力测试工具

    ab是apache自带的一个很好用的压力测试工具,当安装完apache的时候,就可以在bin下面找到ab 1 我们可以模拟100个并发用户,对一个页面发送1000个请求 ./ab -n1000 -c1 ...

  6. Lodop打印如何隐藏table某一列

    Lodop打印超文本,既可以打印页面上存在的某些部分,也可以自己组织超文本和css样式传入,有些需要打印的页面表格里,会有一列有编辑删除等按钮,用于对于数据库数据的操作,在打印的时候,这一列由于不属于 ...

  7. 阿里云 ECS 安全组

    以前在案例云买的ECS我一般都是 连上 ssh,然后把网站文件拿上去 ,安装好需要的环境 然后就可以顺利的打开网站了,这次帮一个朋友买的阿里云ECS让我蒙了, 一切都准备好了 网站打不开 防火墙也检查 ...

  8. js中对URL进行转码与解码

    1. escape 和 unescape escape()不能直接用于URL编码,它的真正作用是返回一个字符的Unicode编码值. 采用unicode字符集对指定的字符串除0-255以外进行编码.所 ...

  9. 官网下载旧版本jdk,老版本jdk,jdk1.7,jdk1.8

    1.进入中文oracle官网(不是国内官网下载速度超级慢): http://www.oracle.com/technetwork/cn/indexes/downloads/index.html 2.进 ...

  10. 【python练习题】程序1

    #题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? count = 0 for i in range(1,5): for j in range(1,5): for k ...