\(\mathcal{Description}\)

  Link.

   \(n\) 个结点的图,\(m\) 条形如 \((u,v,l,r)\) 的边,表示一条连接 \(u\) 和 \(v\) 的无向边会在时间 \((l,r]\) 内存在,时间范围在 \([0,K]\)。判断每个时刻的图是否是二分图。

  \(n,K\le10^5\),\(m\le2\times10^5\)。

\(\mathcal{Solution}\)

  线段树分治其实和线段树没啥关系。(

  个人感觉线段树分治节约时间的方法和整体二分很像——把一些询问都需要的信息统一进行,以减少维护修改操作的次数。线段树二分是在时间轴上二分。记当前时间区间 \([l,r]\),作用所有完全覆盖 \([l,r]\) 的修改(它们是这个区间内的询问都需要的),然后递归左右区间,回溯时撤销当前区间的所有修改。

  对于本题,可以用 \(n+n\) 个虚点的并查集维护二分图——对于一条边 \((u,v)\),合并 \((u,v')\) 和 \((v,u')\)。若 \(u,v\) 在同一集合,显然图上已存在奇环,当前时间区间内的所有询问全部判否,否则递归解答即可。

  复杂度 \(\mathcal O(n\log^2 n)\)。

\(\mathcal{Code}\)

/* Clearink */

#include <cstdio>
#include <vector> inline int rint () {
int x = 0, f = 1; char s = getchar ();
for ( ; s < '0' || '9' < s; s = getchar () ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
return x * f;
} template<typename Tp>
inline void wint ( Tp x ) {
if ( x < 0 ) putchar ( '-' ), x = ~ x + 1;
if ( 9 < x ) wint ( x / 10 );
putchar ( x % 10 ^ '0' );
} const int MAXN = 1e5, MAXM = 2e5;
int n, m, K; struct Edge {
int u, v, l, r;
inline void read () { u = rint (), v = rint (), l = rint (), r = rint (); }
} tmp;
std::vector<Edge> alle; struct DSU {
int fa[MAXN * 2 + 5], siz[MAXN * 2 + 5];
int top, ry[MAXM * 2 + 5], rfa[MAXM * 2 + 5], rsiz[MAXM * 2 + 5];
inline void init () { for ( int i = 1; i <= n << 1; ++ i ) siz[fa[i] = i] = 1; }
inline int find ( const int x ) { return x ^ fa[x] ? find ( fa[x] ) : x; }
inline bool unite ( int x, int y ) {
if ( ( x = find ( x ) ) == ( y = find ( y ) ) ) return false;
if ( siz[x] < siz[y] ) x ^= y ^= x ^= y;
++ top, ry[top] = y, rfa[top] = fa[y], rsiz[top] = siz[x];
return siz[fa[y] = x] += siz[y], true;
}
inline void undo ( const int sta ) {
for ( ; top > sta; -- top ) {
siz[fa[ry[top]]] = rsiz[top];
fa[ry[top]] = rfa[top];
}
}
} dsu; inline void solve ( const int l, const int r, std::vector<Edge>& vec ) {
int mid = l + r >> 1, curs = dsu.top, dis = 0;
std::vector<Edge> vecL, vecR;
for ( auto e: vec ) {
if ( e.l <= l && r <= e.r ) {
if ( dsu.find ( e.u ) == dsu.find ( e.v ) ) {
dis = true, vecL.clear (), vecR.clear ();
break;
}
dsu.unite ( e.u, e.v + n ), dsu.unite ( e.v, e.u + n );
} else {
if ( e.l <= mid ) vecL.push_back ( e );
if ( mid < e.r ) vecR.push_back ( e );
}
}
vec.clear ();
if ( dis ) for ( int i = l; i <= r; ++ i ) puts ( "No" );
else if ( l ^ r ) solve ( l, mid, vecL ), solve ( mid + 1, r, vecR );
else puts ( "Yes" );
dsu.undo ( curs );
} int main () {
n = rint (), m = rint (), K = rint ();
for ( int i = 1; i <= m; ++ i ) {
tmp.read (), ++ tmp.l;
alle.push_back ( tmp );
}
dsu.init (), solve ( 1, K, alle );
return 0;
}

\(\mathcal{Details}\)

  左开右开,左开右闭,左闭右开,左闭右闭……傻傻分不清qwq。

Solution -「洛谷 P5787」「模板」二分图(线段树分治)的更多相关文章

  1. 【洛谷4219】[BJOI2014]大融合(线段树分治)

    题目: 洛谷4219 分析: 很明显,查询的是删掉某条边后两端点所在连通块大小的乘积. 有加边和删边,想到LCT.但是我不会用LCT查连通块大小啊.果断弃了 有加边和删边,还跟连通性有关,于是开始yy ...

  2. Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)

    题面 Bzoj 洛谷 题解 考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治. 具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内 ...

  3. 【洛谷P4585】 [FJOI2015]火星商店问题 线段树分治+可持久化trie

    感觉这个线段树分治和整体二分几乎相同啊~ code: #include <bits/stdc++.h> #define MAX 100300 #define ll long long #d ...

  4. 模板 可并堆【洛谷P3377】 【模板】左偏树(可并堆)

    P3377 [模板]左偏树(可并堆) 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删 ...

  5. 洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)

    To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows con ...

  6. 洛谷 P1083 借教室【二分+差分/线段树】

    二分mid,然后用1~mid的操作在差分序列上加减,最后把差分序列前缀和起来,看是否有有超过初始r值的 #include<iostream> #include<cstdio> ...

  7. 洛谷P4577 [FJOI2018]领导集团问题(dp 线段树合并)

    题意 题目链接 Sol 首先不难想到一个dp,设\(f[i][j]\)表示\(i\)的子树内选择的最小值至少为\(j\)的最大个数 转移的时候维护一个后缀\(mx\)然后直接加 因为后缀max是单调不 ...

  8. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  9. 洛谷.3437.[POI2006]TET-Tetris 3D(二维线段树)

    题目链接 下落一个d*s的方块,则要在这个平面区域找一个最高的h' 更新整个平面区域的值为h+h' 对于本题,维护最大高度h和all 对于平面的x轴维护一棵线段树t1,每个t1的节点维护对应y轴的两棵 ...

随机推荐

  1. Java 单引号 与 双引号 区别

    双引号,用来引用字符串, 单引号用来表示单个字符.

  2. Elasticsearch安装与配置

    一.下载(华为云) https://mirrors.huaweicloud.com/elasticsearch/https://mirrors.huaweicloud.com/kibana/7.6.2 ...

  3. MySQL提权之udf提权(获得webshell的情况)

    什么是udf提权? MySQL提供了一个让使用者自行添加新的函数的功能,这种用户自行扩展函数的功能就叫udf. 它的提权原理也非常简单!即是利用了root 高权限,创建带有调用cmd的函数的udf.d ...

  4. java计算器(简单版)

    前言 之前在学习完Java的方法后,我发现自己可以开始写计算器这个"经典"的项目了,于是我花了一点时间写下了这个计算器的程序,也写下了这篇文章. 在这里,我需要说明一下,这个程序只 ...

  5. Android学习笔记5

    SharedPreferenced的使用方法:SharedPreferences 是一个轻量级的存储类,主要是保存一些小的数据,一些状态信息 第一步:初始化         * 获取SharedPre ...

  6. redis实现简易在线聊天室

    redis_flask简易聊天室 项目构建 这时一个基于Redis数据库的简单小项目,使用redis缓存数据,并通过flask部署到浏览器,运行截图如下: 输入名字后,就可以登陆到聊天室,主要包括三个 ...

  7. python中的rpc库

    基于xml的rpc调用 rpcserver.py from xmlrpc.server import SimpleXMLRPCServer # python中类的命名方式遵循驼峰命名法 # 1. 没有 ...

  8. centos7无法访问虚拟机web服务

    第一种: 先看下防火墙状态:firewall-cmd --state 关闭防火墙再试试:systemctl stop firewalld.service 第二种,不想关闭防火墙 放开http服务 fi ...

  9. 平滑增加Nginx模块

    目录 一:平滑增加Nginx模块 1.1.增加模块必须重新编译 一:平滑增加Nginx模块 1.1.增加模块必须重新编译 解决依赖 编译安装不能解决依赖 yum install zlib zlib-d ...

  10. VUE3 之 插槽的使用 - 这个系列的教程通俗易懂,适合新手

    1. 概述 非理性定律告诉我们: 人们总是习惯于以情感去判断眼前的事物,非理性的去做决定. 对于长远的利益,人们更愿意去选择短期的利益. 因此在做决定前要让自己冷静,理性的分析,让自己看的更远. 言归 ...