@

题意:

链接

题目类似: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 可撤销并查集(栈)+线段树的更多相关文章

  1. 2019牛客第八场多校 D_Distance 三维BIT或定期重建套路

    目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)D_Distance) 题意: 在三维空间\((n\times m\times h\le 100000)\)内,有\(q(q\le 100 ...

  2. 牛客第三场多校 E Sort String

    链接:https://www.nowcoder.com/acm/contest/141/E来源:牛客网 Eddy likes to play with string which is a sequen ...

  3. 牛客第三场多校 H Diff-prime Pairs

    链接:https://www.nowcoder.com/acm/contest/141/H来源:牛客网 Eddy has solved lots of problem involving calcul ...

  4. 牛客第五场多校 J plan 思维

    链接:https://www.nowcoder.com/acm/contest/143/J来源:牛客网 There are n students going to travel. And hotel ...

  5. 牛客第五场多校 A gpa 分数规划(模板)

    链接:https://www.nowcoder.com/acm/contest/143/A来源:牛客网 Kanade selected n courses in the university. The ...

  6. 牛客小白月赛12 H 华华和月月种树 (离线dfs序+线段树)

    链接:https://ac.nowcoder.com/acm/contest/392/H 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 131072K,其他语言2621 ...

  7. PACM Team(牛客第三场多校赛+dp+卡内存+打印路径)

    题目链接(貌似未报名的不能进去):https://www.nowcoder.com/acm/contest/141/A 题目: 题意:背包题意,并打印路径. 思路:正常背包思路,不过五维的dp很容易爆 ...

  8. 牛客第八场 C-counting paths 树形dp计数

    题目地址 题意 给你一颗树 初始点颜色全部为白色 对于每一个满足要求一的点集s f(s)的定义为先把点集内的点染黑 满足要求二的路径集合数量 要求一为两两黑点之间不能出现白色的点 要求二为将这个路径集 ...

  9. 2020牛客寒假算法基础集训营3 - G. 牛牛的Link Power II(线段树)

    题目链接:牛牛的Link Power II 题意:给你一个只含$0$和$1$的串,定义串的$Link$值为串中两个的$1$之间的距离的和,$(u,v)$和$(v,u)$被看认为是同一对,有$m$次操作 ...

随机推荐

  1. JDK 与 JRE

    JDK就是Java Development Kit.简单的说JDK是面向开发人员使用的SDK,它提供了Java的开发环境和运行环境.SDK是Software Development Kit 一般指软件 ...

  2. spring boot 尚桂谷学习笔记09 数据访问

    springboot 与数据库访问 jdbc, mybatis, spring data jpa,  1.jdbc原生访问 新建项目 使用 springboot 快速构建工具 选中 web 组件 sq ...

  3. JQuery判断radio(单选框)是否选中和获取选中值

    一.设置选中方法 代码如下: $("input[name='名字']").get(0).checked=true; $("input[name='名字']"). ...

  4. equals方法重写

    在java中常见的equals方法的重写: 举例:一个自定义类ball如下 public class Ball { private String name; private int weight; p ...

  5. Dubbo 系列(07-5)集群容错 - Mock

    Dubbo 系列(07-5)集群容错 - Mock [toc] Spring Cloud Alibaba 系列目录 - Dubbo 篇 1. 背景介绍 相关文档推荐: Dubbo 实战 - 服务降级 ...

  6. mongo数据库基本查询语句

    D:\MongoDB\Server\3.4\bin>mongo MongoDB shell version v3.-g83c3022fe4 connecting to: mongodb://12 ...

  7. webstorm的下载、破解、与汉化

    其实很简单的事情,都被我弄复杂了倒腾了很久,特做个记录. 说明前提,版本为 webstorm 2018.1.4 一.下载webstorom 下载地址:当然去官网啊  https://www.jetbr ...

  8. python系列——文件操作

    打开和关闭 示例:python系列——文件操作的代码 打开模式 读取 写入

  9. Pxe自动化安装

    Centos7环境 Systemctl stop firewalld Setenforce Yum本地源 cd /etc/yum.repos.d/ 进入/etc/yum.repos.d/ Ls 查看 ...

  10. Pandas之loc\iloc\ix

    ---------------------------------------------------------------------------------------------------- ...