题目描述

题解

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

这道题意图很显然,动态维护联通块,有一个经典做法就是用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. Linux 典型应用之常用命令

    软件操作相关命令 软件包管理 (yum) 安装软件 yum install xxx(软件的名字) 如 yum install vim 卸载软件 yum remove xxx(软件的名字) 如 yum ...

  2. jQuery EasyUI 选项卡面板tabs使用实例精讲

    1. 对选项卡面板区域 div 设置 class=”easyui-tabs” 2. 对选项卡面板区域添加多个 div,每个 div 就是一个选项卡(每个面板一定设置 title) 3. 设置面板 fi ...

  3. Hbase数据结构模型

  4. groovy安装 ideal

    参考:https://blog.csdn.net/newbie_907486852/article/details/80879745 (1) 首先下载groovy: https://gradle.or ...

  5. Python实现百度贴吧自动顶贴机

    开发这款小工具,我们需要做一些准备: url.txt:多个需要顶起的帖子地址. reply:多条随机回复的内容. selenium:浏览器自动化测试框架 首先,我们先使用pip完成selenium的安 ...

  6. 老男孩python学习自修第十九天【异常处理】

    1.常见的错误 TypeError 类型错误 NameError 没有该变量 ValueError 不期望的值 AttributeError 没有该属性 UnboundLocalError 没有该局部 ...

  7. String、StringBuffer、StringBuilder三种类型的一点比较

    简要记一点 以运行速度来说: StringBuilder>StringBuffer>String 以线程安全来说: StringBuilder线程不安全,而StringBuffer线程安全 ...

  8. qtp 自动化测试--点滴 菜单没有了,有些控件运行时找不到

    test项目页签下-没有了 菜单栏:file edit view insert 看不到了 1 解决:在startpage标签下-tool-option-点击 restore layout-确定 2 菜 ...

  9. Attention Model

    参考1: https://blog.csdn.net/malefactor/article/details/50550211 attention部分实现:  https://blog.csdn.net ...

  10. How to install rime on Debian

    apt-get install ibus ibus-rime librime-data-wubi reboot cp ~/.config/ibus/rime/default.yaml ~/.confi ...