@

题意:

链接

题目类似: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. [CSP-S模拟测试]:壕游戏(费用流)

    题目传送门(内部题18) 输入格式 第一行包括四个数$n,m,k,s$表示有$n$个剧情点,$m$个关卡,要玩$k$次游戏,$s$个完结点接下来一行包含$s$个数,代表$s$个完结点的编号.接下来$m ...

  2. 二次封装arcgis的timeslider

    arcgis的timeslider是对dojo slider二次封装,项目需要,所有Map用统一样式的slider,所以写了一个common的dojo class,统一调用生成slider,作为对ti ...

  3. git修改commiter date

    GIT: change commit date to author date git filter-branch --env-filter 'export GIT_COMMITTER_DATE=&qu ...

  4. centos7不能远程登陆的方案

    网上找了很多,就算百度经验写的都是坑,代码如下: BROWSER_ONLY=no BOOTPROTO=static DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INI ...

  5. 面试题:Nginx 是如何实现高并发?常见的优化手段有哪些?

    面试题: Nginx 是如何实现并发的?为什么 Nginx 不使用多线程?Nginx常见的优化手段有哪些?502错误可能原因有哪些? 面试官心理分析 主要是看应聘人员的对NGINX的基本原理是否熟悉, ...

  6. 14. Jmeter-配置元件一

    jmeter-配置元件介绍与使用 CSV 数据文件设置 HTTP信息头管理器 HTTP Cookie 管理器 HTTP Cache Manager HTTP请求默认值 计数器 DNS Cache Ma ...

  7. 斯坦福【概率与统计】课程笔记(六):EDA | 标准差和方差

    这一篇比较简单,就不展开记录了,方差和标准差的计算方法记住了就可以. 计算mean 计算每个样本与mean的差值的平方,将其累加后除以(样本数-1)[注:这里的除数可以是n-1也可以是n],即得到方差 ...

  8. 【mySQL】left join、right join和join的区别

    哈,好久没更新文章了,今天来说说关于mySQL那些年的小事.说到mySQL啊,用了挺久的了,但是有个问题一直在困扰着我,就是left join.join.right join和inner join等等 ...

  9. 杯子(glass)

    题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒 ...

  10. element UI的使用

    npm install --save element-ui main.js里面添加 import ElementUI from 'element-ui' import 'element-ui/lib/ ...