题目描述

题解

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

这道题意图很显然,动态维护联通块,有一个经典做法就是用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. Visual Studio 2010 Shortcuts

    Uploaded by ProNotion, updated on 11/28/2013 by jmb Platform: Windows/ English  PDF    Print   Hide ...

  2. vuex的购物车效果 index.js

    import Vue from 'vue'; import Vuex, { Store } from 'vuex'; import { stat } from 'fs'; Vue.use(Vuex); ...

  3. java中的标记接口(标签接口)

    Java中的标记接口(Marker Interface),又称标签接口(Tag Interface),具体是不包含任何方法的接口.在Java中很容易找到标记接口的例子,比如JDK中的Serialzab ...

  4. Vue+min-width实现最大两栏布局

    <style> .fitting-Modal-details{ overflow: hidden; } .detailsContent{ float: left; min-width: 5 ...

  5. Spring boot 将配置文件属性注入到一个bean中

    现在要做的就是将如下配置文件中的内容注入到一个bean 名为Properties中. Redis.properties配置文件中的内容如下: Properties java bean中代码如下,注意注 ...

  6. yml中driver-class-name: com.mysql.jdbc.Driver 解析不到的问题

    当在idea中使用springboot的快捷创建方式时,选中了mysql 和jdbc 那么pom文件中会直接有 <dependency> <groupId>mysql</ ...

  7. python爬虫之线程池和进程池

    一.需求 最近准备爬取某电商网站的数据,先不考虑代理.分布式,先说效率问题(当然你要是请求的太快就会被封掉,亲测,400个请求过去,服务器直接拒绝连接,心碎),步入正题.一般情况下小白的我们第一个想到 ...

  8. git分支操作2

    1.创建分支 git branch <分支名>           会自动复制主分支上的代码. 2.查看当前分支 git branch -v 3.切换分支 git checkout < ...

  9. fiddler 学习笔记1-下载安装、开启、关闭抓包功能

    1 下载安装(安装于C盘之外的空间中) https://www.telerik.com/fiddler 2 开启抓包功能:安装后默认为开启状态 点击 file-capture 或左下角capture ...

  10. has invalid type <class 'numpy.ndarray'>, must be a string or Tensor

    转自: https://blog.csdn.net/jacke121/article/details/78833922 has invalid type <class 'numpy.ndarra ...