2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树
@
题意:
题目类似:CF366D,Gym101652T
本题给你\(n(100000)\)个点\(m(10000)\)条边,每无向边允许通过编号在\([Li,Ri](1\le Li\le Ri\le 1e9)\)内的人,问从\(1\)到\(n\)能通过多少个人。
分析:
赛中艹了30多发暴力无济于事。。。
因为以前做过一道数据范围1000的原题,当时做法好像是离散化后枚举区间暴力跑\(dfs\)查询或者带着区间跑暴力\(BFS\)最后检查一遍。。。
流下了菜鸡的泪水,主要是思维受限了,这很致命。
听说这题可以LCT写,目前只会可撤销并查集+线段树的写法。。

- 上面讲的也很清楚了,把所有的权值离散化一下,然后建一个以权值为关键字的线段树
- 这里提一下,这个线段树和上一场牛客的E题一模一样,是左闭右开线段树,就是每个叶子节点代表的是一段权值区间。这个线段树的解释:here
- 然后线段树上每个节点存的是覆盖当前点的权值区间的所有边。
- 区间更新完之后,把整颗树遍历一遍得出答案。
- 对于从根到叶子节点这段的权值区间中包含的边,用一个并查集维护连通性。
- 回溯时要撤销上面几条边的影响。记录一下合并上一条边的两个根,然后还原他们的\(fa[],rnk[]\)就行。
- 用一个栈记录加入的边即可,后进先出的结构正适合本题的撤销操作。还有,可撤销并查集不能路径压缩,必须按秩合并。
Code
const int MXN = 3e3 + 7;
const int MXE = 2e6 + 7;
int n, m;
vector<int> sum[MXN<<2], vs;
int fa[MXN], rnk[MXN], top;
struct lh {
int fi, se, u, v;
}stak[MXN];
struct lp {
int u, v, l ,r;
}cw[MXN];
void update(int L, int R, int v, int l ,int r, int rt) {
if(L <= l && r <= R) {
sum[rt].eb(v);
return;
}
int mid = (l + r) >> 1;
if(L > mid) update(L, R, v, mid + 1, r, rt<<1|1);
else if(R <= mid) update(L, R, v, l, mid, rt<<1);
else {
update(L, mid, v, l, mid, rt<<1), update(mid + 1, R, v, mid + 1, r, rt<<1|1);
}
}
int Fi(int x) {
return fa[x] == x? x: Fi(fa[x]);
}
int pa, pb, ans;
void build(int l, int r, int rt) {
if(l == r) {
// debug(l, r, Fi(3), Fi(5))
for(auto x: sum[rt]) {
pa = Fi(cw[x].u), pb = Fi(cw[x].v);
if(pa == pb) continue;
// debug(l, r, cw[x].u, cw[x].v)
if(rnk[pa] > rnk[pb]) swap(pa, pb);
fa[pa] = pb;
rnk[pb] += rnk[pa];
stak[++ top] = {rt, x, pa, pb};
}
if(Fi(1) == Fi(n)) ans += vs[l+1] - vs[l];
while(top && stak[top].fi == rt) {//撤销
int x = stak[top].se;
if(rnk[stak[top].u] > rnk[stak[top].v]) {
fa[stak[top].v] = stak[top].v;
rnk[stak[top].u] -= rnk[stak[top].v];
}else {
fa[stak[top].u] = stak[top].u;
rnk[stak[top].v] -= rnk[stak[top].u];
}
-- top;
}
// debug(l, r, Fi(3), Fi(5))
return;
}
int mid = (l + r) >> 1;
// debug(l, r, mid, rt)
for(auto x: sum[rt]) {
pa = Fi(cw[x].u), pb = Fi(cw[x].v);
if(pa == pb) continue;
// debug(pa, pb)
if(rnk[pa] > rnk[pb]) swap(pa, pb);
fa[pa] = pb;
rnk[pb] += rnk[pa];
stak[++ top] = {rt, x, pa, pb};
}
build(l, mid, rt << 1), build(mid + 1, r, rt << 1 | 1);
while(top && stak[top].fi == rt) {//撤销
int x = stak[top].se;
if(rnk[stak[top].u] > rnk[stak[top].v]) {
fa[stak[top].v] = stak[top].v;
rnk[stak[top].u] -= rnk[stak[top].v];
}else {
fa[stak[top].u] = stak[top].u;
rnk[stak[top].v] -= rnk[stak[top].u];
}
-- top;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
// freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
n = read(), m = read();
for(int i = 1; i <= n; ++i) fa[i] = i, rnk[i] = 1;
vs.eb(0);
for(int i = 1; i <= m; ++i) {
cw[i].u =read(), cw[i].v = read();cw[i].l = read(), cw[i].r = read();
vs.eb(cw[i].l), vs.eb(cw[i].r + 1);
}
my_unique(vs);
// for(auto x: vs) printf("%d ", x); printf("\n");
for(int i = 1; i <= m; ++i) {
update(lower_bound(all(vs), cw[i].l) - vs.begin(), upper_bound(all(vs), cw[i].r) - vs.begin() - 1, i, 1, vs.size() - 1, 1);
// debug(lower_bound(all(vs), cw[i].l) - vs.begin(), upper_bound(all(vs), cw[i].r) - vs.begin() - 1, cw[i].u, cw[i].v);
}
build(1, vs.size() - 1, 1);
printf("%d\n", ans);
return 0;
}
两道待补练习题:CF 813F 可撤销并查集+分治,BZOJ 3237 CDQ分治+带撤销并查集
复习带权并查集和可持久化并查集。
2019牛客第八场多校 E_Explorer 可撤销并查集(栈)+线段树的更多相关文章
- 2019牛客第八场多校 D_Distance 三维BIT或定期重建套路
目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)D_Distance) 题意: 在三维空间\((n\times m\times h\le 100000)\)内,有\(q(q\le 100 ...
- 牛客第三场多校 E Sort String
链接:https://www.nowcoder.com/acm/contest/141/E来源:牛客网 Eddy likes to play with string which is a sequen ...
- 牛客第三场多校 H Diff-prime Pairs
链接:https://www.nowcoder.com/acm/contest/141/H来源:牛客网 Eddy has solved lots of problem involving calcul ...
- 牛客第五场多校 J plan 思维
链接:https://www.nowcoder.com/acm/contest/143/J来源:牛客网 There are n students going to travel. And hotel ...
- 牛客第五场多校 A gpa 分数规划(模板)
链接:https://www.nowcoder.com/acm/contest/143/A来源:牛客网 Kanade selected n courses in the university. The ...
- 牛客小白月赛12 H 华华和月月种树 (离线dfs序+线段树)
链接:https://ac.nowcoder.com/acm/contest/392/H 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 131072K,其他语言2621 ...
- PACM Team(牛客第三场多校赛+dp+卡内存+打印路径)
题目链接(貌似未报名的不能进去):https://www.nowcoder.com/acm/contest/141/A 题目: 题意:背包题意,并打印路径. 思路:正常背包思路,不过五维的dp很容易爆 ...
- 牛客第八场 C-counting paths 树形dp计数
题目地址 题意 给你一颗树 初始点颜色全部为白色 对于每一个满足要求一的点集s f(s)的定义为先把点集内的点染黑 满足要求二的路径集合数量 要求一为两两黑点之间不能出现白色的点 要求二为将这个路径集 ...
- 2020牛客寒假算法基础集训营3 - G. 牛牛的Link Power II(线段树)
题目链接:牛牛的Link Power II 题意:给你一个只含$0$和$1$的串,定义串的$Link$值为串中两个的$1$之间的距离的和,$(u,v)$和$(v,u)$被看认为是同一对,有$m$次操作 ...
随机推荐
- CTF | bugku | 速度要快
检查源码时发现有 <!-- OK ,now you have to post the margin what you find --> 检查响应头发现有 flag: 6LeR55qE6L+ ...
- 基于Springmvc的登录权限拦截器
1.什么是拦截器 拦截器是指通过统一拦截从浏览器发往服务端的请求来完成功能的增强. 使用场景:解决请求的共性问题(如:乱码问题,权限验证问题等) 2.拦截器的基本工作原理 springmvc可以通过配 ...
- APIO2010 特别行动队 & 斜率优化DP算法笔记
做完此题之后 自己应该算是真正理解了斜率优化DP 根据状态转移方程$f[i]=max(f[j]+ax^2+bx+c),x=sum[i]-sum[j]$ 可以变形为 $f[i]=max((a*sum[j ...
- java继承方法覆盖
public class TestB { private void f() { System.out.println("TestB"); } public static void ...
- appium常见问题11_小米手机初次启动app,报错255“Requires permission android.permission.WRITE_SECURE_SETTINGS”
问题: 新申请的测试机到啦,申请机型是小米9.打开开发者模式.USB调试后,连接电脑,准备跑一下自动化脚本.但是在pycharm中点击run后,出现报错,报错code:255,提示“Requires ...
- EasyUI 的日期控件单击文本框显示日历
注意:可 用 ctrl+f 搜索 "_outerWidth():0" 1. jQuery.easyui.min.js1.3.2 版本 function _745(_746,_7 ...
- python 装饰器 第十一步:多层装饰器的嵌套
#第十一步:多层装饰器的嵌套 #装饰器1 def kuozhan1(func): #定义装饰之后的函数 def neweat1(): # 扩展功能1 print('1-----饭前洗手') # 调用基 ...
- 蓝桥杯:排它平方数-java
问题描述: 小明正看着 203879 这个数字发呆.原来,203879 * 203879 = 41566646641这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同 ...
- .NET Core TDD 前传: 编写易于测试的代码 一 -- 缝
转载于: https://www.cnblogs.com/cgzl/p/9365955.html 有时候不是我们不想做单元测试, 而是这代码写的实在是没法测试.... 举个例子, 如果一辆汽车在产出后 ...
- c++网络库之 poco
java 不好吗?java面向对象很好啊. poco 做的像 java 用起来更面向对象,这是优势.开发速度提升很多.boost 那种是给大牛看的.我觉得 poco 用起来方便,不清楚的地方随时看源码 ...