【线段树分治】luogu_P5787 二分图 /【模板】线段树分治
时间:2021-08-13
本文章向大家介绍【线段树分治】luogu_P5787 二分图 /【模板】线段树分治,主要包括【线段树分治】luogu_P5787 二分图 /【模板】线段树分治使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题意
有一个\(n\)个节点的图。
在\(k\)时间内有\(m\)条边会出现后消失。
要求出每一时间段内这个图是否是二分图。
\(n,k=10^5,m=2\times 10^5\)。
思路
离线算法。根据时间来分治。
用线段树来保存覆盖了时间段\([l,r]\)的边。
对于当前线段树节点,如果这些边都添➕进图中会使这个图不是二分图,就直接退出。
如果边都➕完了,我们就继续分治,处理没有完全覆盖这个区间的边。
这就相当于在线段树上分治,即线段树分治。
至于判断二分图,可以使用扩展域并查集来处理,并且要支持撤销操作,这个用栈维护再回溯即可。
代码
#include <cstdio>
#include <vector>
int n, m, k, cnt, top;
int u[300001], v[300001], fa[600001], height[600001];
int V[300001];
std::vector<int> dat[1200001];
std::pair<int, int> st[600001];
void insert(int p, int l, int r, int L, int R, int x) {
if (L <= l && r <= R) {
dat[p].push_back(x);
return;
}
int mid = l + r >> 1;
if (L <= mid)
insert(p << 1, l, mid, L, R, x);
if (R > mid)
insert(p << 1 | 1, mid + 1, r, L, R, x);
}
int find(int x) {//注意并查集用按秩合并,路径压缩会影响回溯
return x == fa[x] ? x : find(fa[x]);
}
void merge(int x, int y) {
int f1 = find(x), f2 = find(y);
if (height[f1] > height[f2])
std::swap(f1, f2);
st[++top] = std::make_pair(f1, height[f1] == height[f2]);
fa[f1] = f2;
height[f2] += height[f1] == height[f2];
}
void solve(int p, int l, int r) {
int flag = 1, lastop = top;
for (int i = 0; i != dat[p].size(); i++) {
int tmp = dat[p][i];
int f1 = find(u[tmp]), f2 = find(v[tmp]);
if (f1 == f2) {//不是二分图就不用继续分治,这个时间段都不是二分图
for (int j = l; j <= r; j++)
printf("No\n");
flag = 0;
break;
}
merge(u[tmp], v[tmp] + n);//扩展域
merge(u[tmp] + n, v[tmp]);
}
if (flag) {//覆盖当前区间的边可以
if (l == r)
printf("Yes\n");
else {//继续分治
int mid = l + r >> 1;
solve(p << 1, l, mid);
solve(p << 1 | 1, mid + 1, r);
}
}
while (top > lastop) {
height[fa[st[top].first]] -= st[top].second;
fa[st[top].first] = st[top].first;
top--;
}
}
int main() {
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; i++)
fa[i] = i, fa[i + n] = i + n;
for (int i = 1, l, r; i <= m; i++) {
scanf("%d %d %d %d", &u[i], &v[i], &l, &r);
if (l ^ r)
insert(1, 1, k, l + 1, r, i);
}
solve(1, 1, k);
}
原文地址:https://www.cnblogs.com/HSZGB/p/15138876.html
- 第八章:Shiro和Spring的集成——深入浅出学Shiro细粒度权限开发框架
- 第九章:Shiro的Web——深入浅出学Shiro细粒度权限开发框架
- 第十章:Shiro的Cache——深入浅出学Shiro细粒度权限开发框架
- Appboy基于MongoDB的数据密集型实践
- 微信企业号登录授权Java实现获取员工userid根据userid换openid
- 微信支付-微信红包Java版本
- Universe入门
- 分享一款值得分享的写作工具
- 微信二次开发Java自定义菜单事件实现
- 微信OAuth授权获取用户OpenId-JAVA(个人经验)
- 【手写文字识别】-JavaAPI示例代码
- 【Python3-API】情感倾向分析示例代码
- SpringMVC+Hibernate +MySql+ EasyUI实现CRUD(一)
- 【Python3-API】通用文字识别示例代码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- java中各种距离换算
- SAP Spartacus HttpParamsURIEncoder单元测试文件备份
- 微PE制作U盘启动盘,并安装Win10
- Angular单元测试如何只执行指定的测试用例,提高测试速度
- 院长智能部署Frp内网穿透---支持多系统
- dotnet OpenXML 元素 cNvPr NonVisual Drawing Properties 重复 id 标识处理
- Magicodes.IE之花式导出
- vue列表点击切换颜色
- JVM加载过程科普
- 我没学过计算机,是怎么接了四个私活还挣了两个 iPad 的?
- Helm安装Prometheus Operator
- 【每日一题】【vue2源码学习】vue如何检测数组的变化
- JavaScript 实现输入框内容一键复制(附上 Vue 3 实现方式)
- python 迭代器/iterator与生成器/generator的区别
- CSS 实现文本超出容器范围用省略号显示(单行+多行)