题面

给一个

N

N

N 点

M

M

M 边的简单无向图,询问

Q

Q

Q 次,每次问你把编号在

[

l

i

,

r

i

]

[l_i,r_i]

[li​,ri​] 之间的边删掉后,该图是否存在奇数环,即是否不能被二染色

1

N

,

M

,

Q

200000

1\leq N,M,Q\leq 200000

1≤N,M,Q≤200000.

题解

看了半天才搞懂官解里的奇怪分治是什么,其实就是整体二分嘛!

部分分就不多赘述了,大概就是一步步引导我们到正解的整体二分+可回退并查集(官解称其为:DSU)上。

并查集是经典的解决二染色问题的方法了,每个点存一个值表示自己和父亲的颜色是否不同(0/1),再存一个集合大小,然后用启发式合并保证每次只变动一条边,最后用一个栈来存每次加的边,以备回退之需。

我们发现答案具有包含性,即:若询问为

[

l

,

r

]

[l,r]

[l,r] 时答案是 YES,那么

[

l

,

r

]

[l',r']

[l′,r′] (

[

l

,

r

]

[

l

,

r

]

[l',r']\sub[l,r]

[l′,r′]⊂[l,r])的答案也是 YES ,这个易证,因为能形成奇数环的边都还在。

再换一种思路,我们令

m

a

x

r

[

i

]

maxr[i]

maxr[i] 为区间左端点 l=i+1满足答案是 YES 的最大右端点编号 +1(即此时

[

1

,

i

]

[

m

a

x

r

[

i

]

,

M

]

[1,i]\cup[maxr[i],M]

[1,i]∪[maxr[i],M] 以内的边都保留)。那么对于一个询问

[

l

,

r

]

[l,r]

[l,r] 当且仅当

m

a

x

r

[

l

1

]

>

r

maxr[l-1]>r

maxr[l−1]>r 时答案为 YES。同时,由于之前的包含性,我们可以发现

i

<

j

m

a

x

r

[

i

]

m

a

x

r

[

j

]

i<j\Rightarrow maxr[i]\leq maxr[j]

i<j⇒maxr[i]≤maxr[j]

即:

m

a

x

r

[

i

]

maxr[i]

maxr[i] 单调不降!

为了配合可回退并查集,具体地,我们这样分治:

  1. s

    o

    l

    v

    e

    (

    l

    1

    ,

    r

    1

    ,

    l

    2

    ,

    r

    2

    )

    solve(l_1,r_1,l_2,r_2)

    solve(l1​,r1​,l2​,r2​),四个参数,分别表示两个区间:要求的标号区间

    [

    l

    1

    ,

    r

    1

    ]

    [l_1,r_1]

    [l1​,r1​],以及通过之前的计算已经确定的该区间内针对所有位置

    m

    a

    x

    r

    maxr

    maxr 的范围

    [

    l

    2

    ,

    r

    2

    ]

    [l_2,r_2]

    [l2​,r2​]。为配合并查集,操作前得保证前提条件

    l

    1

    l_1

    l1​ 左边的边和

    r

    2

    r_2

    r2​ 右边的边都已经加入并查集。

  2. 整体二分常规程序,先取

    m

    i

    d

    1

    =

    l

    1

    +

    r

    1

    2

    mid_1=\lfloor\frac{l_1+r_1}{2}\rfloor

    mid1​=⌊2l1​+r1​​⌋,然后把

    [

    l

    1

    ,

    m

    i

    d

    1

    ]

    [l_1,mid_1]

    [l1​,mid1​] 的边都加上,再从

    r

    2

    r_2

    r2​ 开始往前加边,直到存在奇数环,即求出了

    m

    a

    x

    r

    [

    m

    i

    d

    1

    ]

    maxr[mid_1]

    maxr[mid1​]。

  3. m

    i

    d

    2

    =

    m

    a

    x

    r

    [

    m

    i

    d

    1

    ]

    mid_2=maxr[mid_1]

    mid2​=maxr[mid1​],那么我们可以往下转移了,我们知道

    [

    l

    1

    ,

    m

    i

    d

    1

    1

    ]

    [l_1,mid_1-1]

    [l1​,mid1​−1] 的

    m

    a

    x

    r

    maxr

    maxr 一定在

    [

    l

    2

    ,

    m

    i

    d

    2

    ]

    [l_2,mid_2]

    [l2​,mid2​] 以内,以及

    [

    m

    i

    d

    1

    +

    1

    ,

    r

    1

    ]

    [mid_1+1,r_1]

    [mid1​+1,r1​] 的

    m

    a

    x

    r

    maxr

    maxr 一定在

    [

    m

    i

    d

    2

    ,

    r

    2

    ]

    [mid_2,r_2]

    [mid2​,r2​] 以内。

  4. 递归

    s

    o

    l

    v

    e

    (

    m

    i

    d

    1

    +

    1

    ,

    r

    1

    ,

    m

    i

    d

    2

    ,

    r

    2

    )

    solve(mid_1+1,r_1,mid_2,r_2)

    solve(mid1​+1,r1​,mid2​,r2​) 。此前暴力回退、加边使之满足前提条件

  5. 递归

    s

    o

    l

    v

    e

    (

    l

    1

    ,

    m

    i

    d

    1

    1

    ,

    l

    2

    ,

    m

    i

    d

    2

    )

    solve(l_1,mid_1-1,l_2,mid_2)

    solve(l1​,mid1​−1,l2​,mid2​)。同理。

递归到边界就不用多说了吧。

时间复杂度

O

(

M

log

2

M

+

Q

)

O(M\log^2M+Q)

O(Mlog2M+Q)。

CODE

#include<set>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
int U[MAXN],V[MAXN];
vector<int> g[MAXN];
int fa[MAXN],ds[MAXN],siz[MAXN];
int findd(int x) {if(x == fa[x]) return 0;return findd(fa[x])^ds[x];}
int findf(int x) {return x==fa[x] ? x:findf(fa[x]);}
vector<int> st;
bool unionSet(int a,int b) {
int u = findf(a),v = findf(b);
if(siz[u] > siz[v]) swap(u,v),swap(a,b);
int d1 = findd(a),d2 = findd(b);
if(u == v) {
return d1 ^ d2;
}
if(d1 == d2) ds[u] = 1;
else ds[u] = 0;
siz[v] += siz[u]; fa[u] = v;
st.push_back(u);
return 1;
}
void POP() {
int u = st.back(); st.pop_back();
int v = fa[u];
ds[u] = 0; siz[v] -= siz[u];
fa[u] = u; return ;
}
int maxr[MAXN];
int li[MAXN],ri[MAXN];
void solve(int l,int r,int l2,int r2) {
if(l > r || l2 > r2) return ;
if(l2 == r2) {
for(int i = l;i <= r;i ++) maxr[i] = l2;
return ;
}
int mid = (l + r) >> 1,le = (int)st.size(),rr = max(l2,mid-1);
int flag = 0;
for(int i = l;i <= mid;i ++) if(i) flag |= 1^unionSet(U[i],V[i]);
int le2 = (int)st.size();
if(flag) rr = r2;
for(int i = min(r2,m);i > mid && i >= l2 && i > rr;i --) {
flag |= 1^unionSet(U[i],V[i]);
if(flag) {rr = i;break;}
}
maxr[mid] = rr;
while((int)st.size() > le2) POP();
solve(mid+1,r,rr,r2);
while((int)st.size() > le) POP();
for(int i = min(r2,m);i >= rr;i --) unionSet(U[i],V[i]);
solve(l,mid-1,l2,rr);
while((int)st.size() > le) POP();
return ;
}
int main() {
n = read();m = read();int Q = read();
for(int i = 1;i <= m;i ++) {
s = read();o = read();
g[s].push_back(o);
g[o].push_back(s);
U[i] = s; V[i] = o;
}
int rr = 0;
for(int i = 1;i <= Q;i ++) li[i] = read(),ri[i] = read(),rr = max(li[i],rr);
for(int i = 1;i <= n;i ++) fa[i] = i,ds[i] = 0,siz[i] = 1;
solve(0,m,0,m+1);
for(int i = 1;i <= Q;i ++) {
s = li[i];o = ri[i];
if(maxr[s-1] > o) printf("YES\n");
else printf("NO\n");
}
return 0;
}

[CF1386C] Joker (IOI 赛制,分治,整体二分+可回退并查集)的更多相关文章

  1. CQD(陈丹琦)分治 & 整体二分——专题小结

    整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料:       整体二分是个很神的东西 ...

  2. 一篇自己都看不懂的CDQ分治&整体二分学习笔记

    作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...

  3. Cdq分治整体二分学习记录

    这点东西前前后后拖了好几个星期才学会……还是自己太菜啊. Cdq分治的思想是:把问题序列分割成左右两个,先单独处理左边,再处理左边对右边的影响,再单独处理右边.这样可以消去数据结构上的一个log,降低 ...

  4. [学习笔记] CDQ分治&整体二分

    突然诈尸.png 这两个东西好像都是离线骗分大法... 不过其实这两个东西并不是一样的... 虽然代码长得比较像 CDQ分治 基本思想 其实CDQ分治的基本思想挺简单的... 大概思路就是长这样的: ...

  5. 算法笔记--CDQ分治 && 整体二分

    参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...

  6. CDQ分治&整体二分学习个人小结

    目录 小结 CDQ分治 二维LIS 第一道裸题 bzoj1176 Mokia bzoj3262 陌上花开 bzoj 1790 矩形藏宝地 hdu5126四维偏序 P3157 [CQOI2011]动态逆 ...

  7. luogu P5473 [NOI2019]I 君的探险 交互 随机 二分 分治 整体二分

    LINK:I 君的探险 神仙题! 考虑一个暴力的做法 每次点亮一个点 询问全部点 这样询问次数为 \(\frac{n\cdot (n-1)}{2}\) 可以通过前5个点. 考虑都为A的部分分 发现一个 ...

  8. Codeforces 938G Shortest Path Queries [分治,线性基,并查集]

    洛谷 Codeforces 分治的题目,或者说分治的思想,是非常灵活多变的. 所以对我这种智商低的选手特别不友好 脑子不好使怎么办?多做题吧-- 前置知识 线性基是你必须会的,不然这题不可做. 推荐再 ...

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

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

随机推荐

  1. 2020.12.12【NOIP提高B组】模拟 总结

    第一次来 B 组做,虚的很 T1: 容斥原理 比赛时也打了个大致,但挂了,只有 50 分. 赛后重构了一下代码,AC \(UPDATE:2020/12/13\ \ \ 14:10\) 思路: 像前缀和 ...

  2. H2-Table CATALOGS not found

    在使用 IntelliJ IDEA 2021.1.3 版本,使用默认配置连接 H2 数据库的时候,出现下面错误,项目里 H2 使用的版本为 2.0.202 . [42S02][42102] org.h ...

  3. MAUI模板项目闪退问题

    MAUI模板项目闪退问题 在MAUI最初发布的时候就曾创建过几个模板项目进行体验过,没遇到什么坑.由于最近需要开发针对餐饮行业的收银机(安卓系统)开发一款应用,这种收银机一般配置不咋滴,系统版本和性能 ...

  4. 24.Haproxy搭建Web群集

    Haproxy搭建Web群集 目录 Haproxy搭建Web群集 Haproxy简介 常见的Web集群调度器 软件类 硬件类 Haproxy应用分析 HAProxy的主要特性 HAProxy常见的8种 ...

  5. 【python基础】第04回 变量常量

    本章内容概要 1. python 语法注释 2. python 语法之变量常量 3. python 基本数据类型(整型(int),浮点型(float),字符串(str)) 本章内容详解 1. pyth ...

  6. bat-命令行安装软件

    批处理 执行的两种方式 1.直接右键以管理员身份运行 2.在管理员身份的cmd窗口中 .\xxx.bat 执行 区别 第一种方式 当前cmd默认路径为 C:\windows\system32 第二种方 ...

  7. 用python制作文件搜索工具,深挖电脑里的【学习大全】

    咳咳~懂得都懂啊 点击此处找管理员小姐姐领取正经资料~ 开发环境 解释器: Python 3.8.8 | Anaconda, Inc. 编辑器: pycharm 专业版 先演示效果 开始代码,先导入模 ...

  8. plain framework的实际应用和扩展

    首先在这里庆祝香港回归祖国的怀抱25周年,想起那年还是一个小学生戴着红领巾和胸章激动不已,实现祖国的统一是每个中华儿女从小的梦想!趁着这欢庆的日子,突然想要写些什么,其实最近也在做一些事,由于工作繁忙 ...

  9. NC23036 华华听月月唱歌

    NC23036 华华听月月唱歌 题目 题目描述 月月唱歌超级好听的说!华华听说月月在某个网站发布了自己唱的歌曲,于是把完整的歌曲下载到了U盘里.然而华华不小心把U盘摔了一下,里面的文件摔碎了.月月的歌 ...

  10. P1494 小Z的袜子 莫队

    题干 就是将$add$和$del$函数里的$ans$变化变成组合数嘛, 先预处理出$x$只相同袜子一共有$f[x] = 1+2+...+$$(x-1)$种组合, 要注意,由于$f[x]$是一直加到$x ...