Explorer(2019年牛客多校第八场E题+线段树+可撤销并查集)
题目链接
题意
给你一张无向图,每条边\(u_i,v_i\)的权值范围为\([L_i,R_i]\),要经过这条边的条件是你的容量要在\([L_i,R_i]\),现在问你你有多少种容量使得你可以从\(1\)走到\(n\)。
思路
跟着大佬们的代码学了波可撤销并查集和线段树骚操作,感觉自己好菜啊。
首先我们用并查集来维护哪些边的权值范围在线段树结点对应的区间内,用\(vector\)来存下结点编号(注意由于区间范围太大我们需要离散化建左闭右开线段树)。在查询的时候一路向下,将经过的结点存的所有边的编号对应的两个端点用并查集维护连通性,当到达线段树叶子结点时就说明所有包含这个叶子结点对应的区间的边都用并查集维护了,此时再判断\(1\)与\(n\)是否在一个连通块里面,在就将这个区间的长度加到答案里面,不在就说明这个结点对应的区间无法使得从\(1\)走到\(n\),在回溯的时候撤销之前并查集的合并集合操作。
代码
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson (rt<<1),L,mid
#define rson (rt<<1|1),mid + 1,R
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)
const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 200000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
pii st[maxn*4];
int n, m, tot, tp, ans;
vector<int> vec[maxn*4];
int u[maxn], v[maxn], L[maxn], R[maxn];
int num[maxn*2], fa[maxn], sz[maxn];
int fi(int x) {
return fa[x] == x ? x : fi(fa[x]);
}
void merge(int u, int v) {
int x = fi(u), y = fi(v);
if(x == y) {
st[++tp] = {-1, -1}; //按照我的写法不能省略,因为我是根据结点对应的vector的size来撤消的,少了这个那么tp会减到负数导致re。
return;
}
if(sz[x] < sz[y]) swap(x, y);
sz[x] += sz[y];
fa[y] = x;
st[++tp] = {x, y};
}
void cancel() {
int x = st[tp].first;
int y = st[tp--].second;
if(x == -1) return;
sz[x] -= sz[y];
fa[y] = y;
}
void update(int l, int r, int id, int rt, int L, int R) {
if(l <= L && R <= r) {
vec[rt].emplace_back(id);
return;
}
int mid = (L + R) >> 1;
if(r <= mid) update(l, r, id, lson);
else if(l > mid) update(l, r, id, rson);
else {
update(l, mid, id, lson);
update(mid + 1, r, id, rson);
}
}
void query(int l, int r, int rt) {
for(int i = 0; i < (int)vec[rt].size(); ++i) {
int id = vec[rt][i];
merge(u[id], v[id]);
}
if(l == r) {
int x = fi(1), y = fi(n);
if(x == y) {
ans += num[r+1] - num[l];
}
for(int i = 0; i < (int)vec[rt].size(); ++i) {
cancel();
}
return;
}
int mid = (l + r) >> 1;
query(l, mid, rt<<1);
query(mid + 1, r, rt<<1|1);
for(int i = 0; i < (int)vec[rt].size(); ++i) {
cancel();
}
}
int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i) {
scanf("%d%d%d%d", &u[i], &v[i], &L[i], &R[i]);
num[++tot] = L[i];
num[++tot] = R[i] + 1;
}
sort(num + 1, num + tot + 1);
tot = unique(num + 1, num + tot + 1) - num - 1;
for(int i = 1; i <= m; ++i) {
int l = lower_bound(num + 1, num + tot + 1, L[i]) - num;
int r = lower_bound(num + 1, num + tot + 1, R[i] + 1) - num;
update(l, r - 1, i, 1, 1, tot);
}
for(int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
query(1, tot, 1);
printf("%d\n", ans);
return 0;
}
Explorer(2019年牛客多校第八场E题+线段树+可撤销并查集)的更多相关文章
- Distance(2019年牛客多校第八场D题+CDQ+树状数组)
题目链接 传送门 思路 这个题在\(BZOJ\)上有个二维平面的版本(\(BZOJ2716\)天使玩偶),不过是权限题因此就不附带链接了,我也只是在算法进阶指南上看到过,那个题的写法是\(CDQ\), ...
- 2019牛客暑期多校训练营(第八场) E 线段树+可撤销并查集
题目传送门 题意: 给出m条无向边,每条边都有一个$[l,r]$,意思是体积在这个范围内的人才能通过这条边,询问有多少种体积的可能性,能使人从1到n 思路:由于是无向边,1和n的连通性可以用并查集维护 ...
- 2019牛客多校第八场 F题 Flowers 计算几何+线段树
2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...
- 2020牛客多校第八场K题
__int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...
- 2019年牛客多校第四场 B题xor(线段树+线性基交)
题目链接 传送门 题意 给你\(n\)个基底,求\([l,r]\)内的每个基底是否都能异或出\(x\). 思路 线性基交板子题,但是一直没看懂咋求,先偷一份咖啡鸡板子写篇博客吧~ 线性基交学习博客:传 ...
- Palindrome Mouse(2019年牛客多校第六场C题+回文树+树状数组)
目录 题目链接 题意 思路 代码 题目链接 传送门 题意 问\(s\)串中所有本质不同的回文子串中有多少对回文子串满足\(a\)是\(b\)的子串. 思路 参考代码:传送门 本质不同的回文子串肯定是要 ...
- generator 1(2019年牛客多校第五场B题+十进制矩阵快速幂)
目录 题目链接 思路 代码 题目链接 传送门 思路 十进制矩阵快速幂. 代码 #include <set> #include <map> #include <deque& ...
- Find the median(2019年牛客多校第七场E题+左闭右开线段树)
题目链接 传送门 题意 每次往集合里面添加一段连续区间的数,然后询问当前集合内的中位数. 思路 思路很好想,但是卡内存. 当时写的动态开点线段树没卡过去,赛后机房大佬用动态开点过了,\(tql\). ...
- 2019年牛客多校第三场 F题Planting Trees(单调队列)
题目链接 传送门 题意 给你一个\(n\times n\)的矩形,要你求出一个面积最大的矩形使得这个矩形内的最大值减最小值小于等于\(M\). 思路 单调队列滚动窗口. 比赛的时候我的想法是先枚举长度 ...
随机推荐
- Markdown 编辑器指南
一直觉得博客园默认的编辑器不好用,后来了解了Markdown,并且博客园也支持Markdown标记,所以写篇博客总结下. 一.认识 Markdown Markdown 是一种用来写作的轻量级「标记语言 ...
- kali 破解wifi
1.查看网卡名称:iwconfig 有一块 名为wlan0 的无线网卡通过一下命令排除影响因素 root@jkali:~# iwconfig lo no wireless extensions. wl ...
- POJ-图论-最小生成树模板
POJ-图论-最小生成树模板 Kruskal算法 1.初始时所有结点属于孤立的集合. 2.按照边权递增顺序遍历所有的边,若遍历到的边两个顶点仍分属不同的集合(该边即为连通这两个集合的边中权值最小的那条 ...
- 【转】【linux】查看文件夹大小
du的用法 du命令用来查看目录或文件所占用磁盘空间的大小.常用选项组合为:du -sh du常用的选项: -h:以人类可读的方式显示 -a:显示目录占用的磁盘空间大小,还要显示其下目录和文件占用磁盘 ...
- eclipse配置lombok插件
下载lombok-1.16.12.jar包 然后将包添加到eclipse.ini 同级目录下 打开eclipse目录:最后两行添加如下配置: -Xbootclasspath/a:lombok-1.16 ...
- CLH lock 原理及JAVA实现
--喜欢记得关注我哟[shoshana]-- 前记 JUC中的Lock中最核心的类AQS,其中AQS使用到了CLH队列的变种,故来研究一下CLH队列的原理及JAVA实现 一. CLH背景知识 SMP ...
- Java的多路分支代码,感觉有点意思
/** * @Author hty * @Date 2019-12-16 16:39 * @Version 1.0 */ import java.util.Random; // 比赛结果 enum O ...
- 关于FMX 单击出来右键菜单,并显示在当前下面
关于FMX 单击出来右键菜单,并显示在当前下面 procedure TForm1.btn6MouseDown(Sender: TObject; Button: TMouseButton; Shift ...
- FusionInsight大数据开发---Streaming应用开发
Streaming应用开发 掌握Streaming基本业务开发流 熟悉Streaming常用API接口使用 掌握Streaming业务设计基本原则 了解Streaming应用开发环境 了解CQL开发流 ...
- FRP represents an intersection of two programming paradigms.
FRP represents an intersection of two programming paradigms. Functional programming Functional progr ...