CF1801E Gasoline prices 题解

news/2025/1/12 19:34:07/文章来源:https://www.cnblogs.com/Rock-N-Roll/p/18667192

\(\text{CF1801E Gasoline prices 题解}\)

考虑方案数如何计算。注意到树上一些点有着相同的取值,于是如果我们将它们用并查集缩起来,它的可行取值范围就是 \([\max_{l_i},\min_{r_i}]\)。现在考虑并查集的维护方式。考虑只有 \(n\) 个点,这样一来需要合并的点对至多只有 \(O(n)\) 个,也就是我们只需要快速地找到两条路径上所属不同集合的点即可。现在考虑如何处理这玩意。由于总的合并个数只有 \(n\),因此在并查集合并的时候可以顺便启发式合并出每个点现在属于哪个根节点下。这个过程中我们用树上数据结构维护一下信息,查询的时候二分去做一下就行了。看上去很好实现的样子。

然后我们考虑怎么实现。启发式合并直接用 std::set 就可以暴力做。对于一条路径我们可以拆成两条链,分类讨论维护一下信息即可。这个树上数据结构第一想法是线段树结合树链剖分,但这样一来内层的复杂度是 \(O(\log^2n)\) 的,总的复杂度是 \(O(n\log^3 n)\),亲测过不去。考虑维护的实际上是一条链的信息,能够做贡献的只有父亲节点,于是考虑维护每个点对于子树内的贡献,查询的时候差分一下就行了,总的时间复杂度是 \(O(n\log^2n)\),略微卡常。看上去很好实现的样子,只有区区 4.5 KiB。

#include <bits/stdc++.h>
#define N 200005
#define M 18
#define ull unsigned long long
#define ll long long
#define mod 1000000007
using namespace std;
ll qpow(ll x) {ll y = mod - 2, ans = 1;while (y) {if (y & 1) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}
int n;
struct node {int to, nxt;
} t[N];
int head[N], cnt;
void add(int u, int v) {t[++cnt].to = v;t[cnt].nxt = head[u];head[u] = cnt;
} 
int dfn[N], rk[N], tot;
int dep[N], siz[N], anc[M][N], top[N], son[N], f[N];
int tpt;
void dfs1(int x, int fa) {f[x] = anc[0][x] = fa;dep[x] = dep[fa] + 1;siz[x] = 1;for (int i = head[x]; i; i = t[i].nxt) {int y = t[i].to;dfs1(y, x);siz[x] += siz[y];if (siz[son[x]] < siz[y]) son[x] = y;}
}
void dfs2(int x, int tp) {dfn[x] = ++tot;rk[tot] = x;top[x] = tp;if (!son[x]) return;dfs2(son[x], tp);for (int i = head[x]; i; i = t[i].nxt) if (t[i].to != son[x])dfs2(t[i].to, t[i].to);
}
int LCA(int x, int y) {while (top[x] != top[y]) {if (dep[top[x]] < dep[top[y]]) swap(x, y);x = f[top[x]];}return dep[x] > dep[y] ? y : x;
}
const ull bas = 131;
ull fac[N], inv[N];
int tqt;
struct BIT {int lbt(int x) {return x & (-x);}ull tree[N];void ad(int x, ull vl) {++tqt;while (x <= n) tree[x] += vl, x += lbt(x);}void add(int x, int y, ull vl) {ad(x, vl);ad(y + 1, -vl);}ull ask(int x) {++tqt;ull ans = 0;while (x) ans += tree[x], x -= lbt(x);return ans;}
} U, D;
ll ans = 1;
int ml[N], mr[N];
struct DSU {int fa[N];int fnd(int x) {return x == fa[x] ? x : fa[x] = fnd(fa[x]);}set<int>st[N];int l[N], r[N];void mge(int x, int y) {x = fnd(x), y = fnd(y);if (x == y) return;if (st[x].size() < st[y].size()) swap(x, y);fa[y] = x;ans = ans * qpow(r[x] - l[x] + 1) % mod;ans = ans * qpow(r[y] - l[y] + 1) % mod;l[x] = max(l[x], l[y]), r[x] = min(r[x], r[y]);ans = ans * max(r[x] - l[x] + 1, 0) % mod;for (auto i : st[y]) {st[x].insert(i);U.add(dfn[i], dfn[i] + siz[i] - 1, (x - y) * fac[dep[i]]);D.add(dfn[i], dfn[i] + siz[i] - 1, (x - y) * inv[dep[i]]);}st[y].clear();}void init() {for (int i = 1; i <= n; i++) {fa[i] = i;l[i] = ml[i], r[i] = mr[i];ans = ans * (mr[i] - ml[i] + 1) % mod;U.add(dfn[i], dfn[i] + siz[i] - 1, i * fac[dep[i]]);D.add(dfn[i], dfn[i] + siz[i] - 1, i * inv[dep[i]]);st[i].insert(i);}}
} dsu;
ull gt(int x, int y) { return (U.ask(dfn[x]) - U.ask(dfn[f[y]])) * inv[dep[y]];
}
ull tg(int x, int y) {return (D.ask(dfn[y]) - D.ask(dfn[f[x]])) * fac[dep[y]];
}
vector<int>v[N];
int gtk(int x, int k) {++tpt;for (int i = M - 1; i >= 0; i--)if ((k >> i) & 1) x = anc[i][x];return x;
}
ull fnd(int x, int y, int k, int l) {if (dep[l] + k <= dep[x]) {int p = gtk(x, k);return gt(x, p);} ull ans = gt(x, l);k -= dep[x] - dep[l];int p = gtk(y, dep[y] - dep[l] - k);return ans * fac[k] + tg(gtk(y, dep[y] - dep[l] - 1), p);
}
int fd(int x, int y, int k, int l) {if (dep[l] + k <= dep[x]) return gtk(x, k);k -= dep[x] - dep[l];int p = gtk(y, dep[y] - dep[l] - k);return p;
}
ull qw(ull x, ull y) {ull ans = 1;while (y) {if (y & 1) ans *= x;x *= x;y >>= 1;}return ans;
}
int main() {fac[0] = inv[0] = 1;for (int i = 1; i < N; i++) fac[i] = fac[i - 1] * bas;ull ivb = qw(fac[1], ULONG_LONG_MAX);for (int i = 1; i < N; i++) inv[i] = inv[i - 1] * ivb;ios::sync_with_stdio(0);cin.tie(0);cin >> n;for (int i = 2; i <= n; i++) {int x;cin >> x;add(x, i);}for (int i = 1; i <= n; i++) cin >> ml[i] >> mr[i];for (int i = 0; i <= n; i++) {for (int j = M - 1; j >= 0; j--)if ((i >> j) & 1)v[i].push_back(j);}dfs1(1, 0);dfs2(1, 1);for (int j = 1; j < M; j++)for (int i = 1; i <= n; i++)anc[j][i] = anc[j - 1][anc[j - 1][i]];dsu.init();int q;cin >> q;while (q--) {int a, b, c, d;cin >> a >> b >> c >> d;if (ans == 0) {cout << "0\n";continue;}int la = LCA(a, b), lc = LCA(c, d), lh = dep[a] + dep[b] - 2 * dep[la];while (fnd(a, b, lh, la) != fnd(c, d, lh, lc)) {int l = 0, r = lh, mid = 0, as = 0;while (l <= r) {mid = (l + r) >> 1;if (fnd(a, b, mid, la) != fnd(c, d, mid, lc)) as = mid, r = mid - 1;else l = mid + 1;} int na = fd(a, b, as, la), nc = fd(c, d, as, lc);dsu.mge(na, nc);}cout << ans << "\n";}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/868315.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024秋季学期 光学期末复习笔记

累了,懒得写文案了参考资料 [1] 赵凯华, 钟锡华. 光学(重排本)[M]. 北京大学出版社, 2017.10. [2] 崔宏滨, 李永平, 康学亮. 光学(第二版)[M]. 科学出版社, 2015.7. [3] 王安廷. 光学课程PPT[Z]. 中国科学技术大学, 2024. 干涉衍射偏振

Python 基础知识 之 选择(分支)结构 + 模式匹配结构(match)

选择结构按照条件选择执行不同的代码段1. 单分支结构if语法结构执行流程:如果表达式的值为True,就执行语句块,如果表达式的值为False,就跳过语句块,继续执行下面的语句 ⭐注意: ⭐⭐⭐表达式后面的冒号; 缩进,python中通过缩进来控制程序逻辑示例;# 1. 判断是否中奖 n…

中考英语优秀范文-热点话题-传统文化-003 Chinese Tea 中国茶

1 写作要求 第三次法国国际友好交流学校线上论坛拟于下周五举行。本期论坛的主题为“茶文化”,作为论坛特邀嘉宾,请你写一篇文章,向国际友好交流学校介绍中国的特色茶饮和中国茶文化。 内容包括: 1 茶的历史(中国人种茶、饮茶已有4000多年的历史)和种类(绿茶、红茶、乌龙…

Hetao P3804 Cut 题解 [ 蓝 ] [ AC 自动机 ] [ 差分 ]

AC 自动机简单题。Cut:AC 自动机简单题。思路 看见多个模式串以及求前缀,很显然能想到构建一个 AC 自动机。 那么在用 \(T\) 查询时,当前指针的深度就是该位置的最长前缀匹配长度。这个在字典树 insert 的时候就能求出来。 求出每一位的最长前缀后,因为这些部分都不能作为分…

Lec 14 文件系统与设备

Lec 14 文件系统与设备License 本内容版权归上海交通大学并行与分布式系统研究所所有 使用者可以将全部或部分本内容免费用于非商业用途 使用者在使用全部或部分本内容时请注明来源 资料来自上海交通大学并行与分布式系统研究所+材料名字 对于不遵守此声明或者其他违法使用本内…

Java基础学习(七)

Java基础学习(七):异常机制 目录Java基础学习(七):异常机制概念简单分类异常体系结构异常处理机制自定义异常 本文为个人学习记录,内容学习自 狂神说Java概念异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等 异常发生在程序运行期…

24. 基于项的控件

一、基于项的控件PySide6 有专门的显示数据的控件和存储数据的模型,可以显示和存储不同形式的数据。显示数据的控件分为两类,一类是基于 项(item)的控件,另一类是基于 模型(model)的控件,基于项的控件是基于模型的控件的简便类。基于项的控件把读取到的数据存储到项中,…

杂题选记

杂题选记在网上天天划水刷面经,见到 teaser 就记下来。我的想法是,把 8L 倒入 3L,把 3L 倒入 5L,把 8L 倒入 3L,把 3L 倒入 5L,这时候三个瓶子分别有 1L(8L) 2L(3L) 5L(5L) 括号里面表示瓶子最开始的容量。这时候把 1L 水倒掉,把容积为 8L 的瓶子里面的 2L 水倒到 容积为…

pytorch算子调用过程:以rand算子为例

通过pytorch的torch.profiler带调用栈采集运行过程可以看到如下信息,通过chrome://tracing查看,图上每个小条条表示一个traceEvent, json中的信息如下图所示,其中cat表示traceEvent的类型,有cpu_op,python_function等,前者表示torch的cpp代码中定义的操作,后者表示pytorc…

Wordpress更换域名后,网站显示框架和加载问题解决

最近建立了一个站点,由于先使用ip进行网站搭建,经过一段时间备案完成后,需要转成域名。直接在Wordpress后台操作后,直接导致网页框架显示异常,排版错乱,大概就是主题的框架无法加载导致的。 搞了很久,包括恢复数据库和重新建站都是这样,最终发现是伪静态的问题。 我是使…

【Weblogic T3协议】反序列化漏洞分析(上)

免责声明 此文章中所涉及的技术、思路和工具仅供网络安全学习为目的,不得以盈利为目的或非法利用,否则后果自行承担!一、前言 在初入安全的时候,就听说过weblogic的大名,当然听说的并不是weblogic如何如何好用,而是因为其漏洞出现频率实在是有点高...于是乎,便抱着学习的…

关于安卓edge无法播放Wordpress上传的mp4视频问题

使用默认插件上传后,电脑端可以播放视频,其他手机浏览器均可播放视频,但是安卓edge无法加载视频。 大概是如下图样子:经查发现电脑打开页面会显示站点部分不安全的提示,说明edge端做了一些阻挡处理,导致视频无法播放。找了一些资料后,发现可以自行修改加载视频的代码框架…