当前位置: 首页 > news >正文

题解:P12653 [KOI 2024 Round 2] 分数竞赛

题意

给定一棵 \(n\) 个点的树,边有权值。对于一条从 \(u\)\(v\) 的路径:

  • 初始时 \(s=0,c=0\)
  • 每经过一条权值为 \(w\) 的边,令 \(s\gets s+w\)。若 \(s<0\),则令 \(s\gets 0,c\gets c+1\)

对于每个点 \(u\),求出所有从 \(u\) 出发的路径的 \(s\) 之和与 \(c\) 之和。\(n\leq 3\times 10^5\)

题解

容易将 \(c\) 转化为严格前缀最小值个数,\(s\) 转化为路径边权和减去最小前缀和。

对于一条从 \(u\)\(v\) 的路径,定义 \(\operatorname{sum}(u,v)\) 为路径边权和,\(\operatorname{minpre}(u,v)\) 为最小前缀和,\(\operatorname{cnt}(u,v)\) 为路径上的严格前缀最小值个数。考虑点分治,尝试合并 \(u\) 走到 \(rt\) 的信息和 \(rt\) 走到 \(v\) 的信息:

\[\begin{align*} \operatorname{sum}(u,v)&=\operatorname{sum}(u,rt)+\operatorname{sum}(rt,v)\\ \operatorname{minpre}(u,v)&=\min(\operatorname{minpre}(u,rt),\operatorname{sum}(u,rt)+\operatorname{minpre}(rt,v))\\ \operatorname{cnt}(u,v)&=\operatorname{cnt}(u,rt)+\sum_{x\in\operatorname{path}(bel_v,v)}[\operatorname{sum}(rt,x)<\operatorname{minpre}(rt,fa_x)][\operatorname{sum}(u,rt)+\operatorname{sum}(rt,x)<\operatorname{minpre}(u,rt)] \end{align*} \]

其中 \(bel_v\) 表示 \(v\) 位于 \(rt\) 的哪个儿子的子树中。

先来做第一问,我们要求 \(\sum\limits_v \operatorname{sum}(u,v)-\operatorname{minpre}(u,v)\)。拆成两部分之差,前者是容易求的。对于后者,考察 \(\operatorname{minpre}(u,v)\) 取到 \(\operatorname{minpre}(u,rt)\) 的条件是 \(\operatorname{minpre}(u,rt)-\operatorname{sum}(u,rt)\leq \operatorname{minpre}(rt,v)\),取到 \(\operatorname{sum}(u,rt)+\operatorname{minpre}(rt,v)\) 的条件则反之。那么用一棵动态开点权值线段树维护 \(\operatorname{minpre}(rt,v)\) 的个数和总和即可。

再来做第二问,我们要求 \(\sum\limits_v \operatorname{cnt}(u,v)\)。考察 \(\sum\) 内部的两个条件,第一个条件是容易判断的,对于第二个条件,将其变为 \(\operatorname{sum}(rt,x)<\operatorname{minpre}(u,rt)-\operatorname{sum}(u,rt)\)。可以得到一个做法:对于每一个 \(v\),枚举 \(\operatorname{path}(bel_v,v)\) 上的点 \(x\),将 \(\operatorname{sum}(rt,x)\) 插到另一棵维护个数的动态开点权值线段树中。反过来考虑,对于每个 \(x\),有 \(sz_x\)\(v\) 可以贡献到它,改为在 \(\operatorname{sum}(rt,x)\) 的位置单点加 \(sz_x\) 即可。

还需要求出 \(u\) 走到 \(rt\) 的信息和 \(rt\) 走到 \(v\) 的信息。后者是容易递推求出的。对于前者,考虑找到 \(u\) 最深的祖先 \(anc_u\) 使得 \(\operatorname{sum}(u,rt)<\operatorname{sum}(anc_u,rt)\),其意义为从 \(u\) 出发向 \(rt\) 走,第一个严格前缀最小值的位置。那么 \(u\) 处维护的三个信息都可以从 \(anc_u\) 处递推得出。求出 \(anc_u\) 可以直接倍增跳,也可以维护一个根链上的单调栈,在单调栈上二分,注意需要用 \(\log\) 的代价让单调栈可撤销。

具体实现时可以遍历 \(rt\) 的每个儿子 \(v\),先更新子树内的点的答案,再加入子树内点的贡献,正反各跑一次。

这样我们得到了 \(\mathcal{O}(n\log{n}\log{V})\) 的做法,常数很大。

可以每次分治把所有 \(\operatorname{minpre}(rt,u)\)\(\operatorname{sum}(rt,u)\) 拿出来离散化,把动态开点权值线段树改成权值 BIT。这样时间复杂度变成了 \(\mathcal{O}(n\log^2{n})\),常数较小,足以通过本题。

代码
#include <bits/stdc++.h>using namespace std;using ll = long long;
using i128 = __int128;
using ui = unsigned int;
using ull = unsigned long long;
using u128 = unsigned __int128;
using ld = long double;
using pii = pair<int, int>;
using pil = pair<int, ll>;
const int N = 3e5 + 5;template<typename T> inline T lowbit(T x) { return x & -x; }
template<typename T> inline void chk_min(T &x, T y) { if (y < x) x = y; }
template<typename T> inline void chk_max(T &x, T y) { if (x < y) x = y; }int n, rt, sz[N];
int sgt1_rt, sgt2_rt;
int stmp, dfn[N], rdfn[N];
int top, stk[N], up[N];
int szd; ll d[N << 1];
ll S[N], C[N];
ll sum[N], mn_pre1[N], mn_pre2[N];
int cnt1[N], cnt2[N];
bool del[N], is_pre[N];
vector<pii> T[N];struct BIT {ll c[N << 1];void init() { fill(c + 1, c + szd + 1, 0); }ll query(int x) {ll res = 0;while (x) res += c[x], x -= lowbit(x);return res;}void add(int x, ll v) { while (x <= szd) c[x] += v, x += lowbit(x); }
} ft1, ft2, ft3;void dfs_rt(int x, int fx, int sz_rt) {sz[x] = 1;int mxp = 0;for (auto [y, z] : T[x]) if (y != fx && !del[y]) {dfs_rt(y, x, sz_rt);sz[x] += sz[y], chk_max(mxp, sz[y]);}chk_max(mxp, sz_rt - sz[x]);if (mxp <= sz_rt >> 1) rt = x;
}
void dfs_calc(int x, int fx) {sz[x] = 1, rdfn[dfn[x] = ++stmp] = x;int tmp = top;int pos = lower_bound(stk + 1, stk + top + 1, x, [&](int x, int y) {return sum[x] > sum[y];}) - stk;int val = stk[pos];up[x] = stk[pos - 1], stk[top = pos] = x;for (auto [y, z] : T[x]) if (y != fx && !del[y]) {sum[y] = sum[x] + z;mn_pre1[y] = min(mn_pre1[x], sum[y]);cnt1[y] = cnt1[x] + (is_pre[y] = sum[y] < mn_pre1[x]);d[++szd] = mn_pre1[y], d[++szd] = sum[y];dfs_calc(y, x);sz[x] += sz[y];}stk[pos] = val, top = tmp;
}
void dfs_solve(int x, int sz_rt) {dfs_rt(x, 0, sz_rt), del[x = rt] = 1;stmp = szd = 0;sum[x] = mn_pre1[x] = cnt1[x] = is_pre[x] = mn_pre2[x] = cnt2[x] = 0;dfs_calc(x, 0);sort(d + 1, d + szd + 1), szd = unique(d + 1, d + szd + 1) - d - 1;auto pos = [&](ll v) {return upper_bound(d + 1, d + szd + 1, v) - d - 1;};for (int i = dfn[x] + 1; i < dfn[x] + sz[x]; ++i) {int p = rdfn[i];S[x] += sum[p] - mn_pre1[p], C[x] += cnt1[p];}int c = 0; ll s = 0;auto calc_sub = [&](int y, bool flag) {for (int i = dfn[y]; i < dfn[y] + sz[y]; ++i) {int p = rdfn[i];if (flag) {if (!up[p]) mn_pre2[p] = cnt2[p] = 0;else {mn_pre2[p] = mn_pre2[up[p]] + sum[p] - sum[up[p]];cnt2[p] = cnt2[up[p]] + 1;}S[p] += sum[p] - mn_pre2[p], C[p] += cnt2[p];}S[p] += sum[p] * c + s;int tmp = pos(mn_pre2[p] - sum[p] - 1);int c2 = ft1.query(tmp); ll s2 = ft2.query(tmp);int c1 = ft1.query(szd) - c2;S[p] -= mn_pre2[p] * c1;S[p] -= sum[p] * c2 + s2;C[p] += (ll)cnt2[p] * c + ft3.query(tmp);}};auto add_sub = [&](int y) {for (int i = dfn[y]; i < dfn[y] + sz[y]; ++i) {int p = rdfn[i];ft1.add(pos(mn_pre1[p]), 1), ft2.add(pos(mn_pre1[p]), mn_pre1[p]);if (is_pre[p]) ft3.add(pos(sum[p]), sz[p]);++c, s += sum[p];}};for (auto [y, z] : T[x]) if (!del[y]) calc_sub(y, 1), add_sub(y);ft1.init(), ft2.init(), ft3.init();c = s = 0;for (int i = T[x].size() - 1; ~i; --i) {auto [y, z] = T[x][i];if (!del[y]) calc_sub(y, 0), add_sub(y);}ft1.init(), ft2.init(), ft3.init();for (auto [y, z] : T[x]) if (!del[y]) dfs_solve(y, sz[y]);
}int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> n;for (int i = 1, u, v, w; i < n; ++i) {cin >> u >> v >> w;T[u].emplace_back(v, w), T[v].emplace_back(u, w);}dfs_solve(1, n);cout << "1\n";for (int i = 1; i <= n; ++i) cout << S[i] << " \n"[i == n];for (int i = 1; i <= n; ++i) cout << C[i] << " \n"[i == n];return 0;
}
http://www.jsqmd.com/news/360927/

相关文章:

  • GROMACS 用 GPU 加速:分子动力学模拟该怎么选显卡?
  • 2026年知名的生态板/橱柜生态板品牌厂家推荐哪家强 - 品牌宣传支持者
  • 不踩雷!更贴合MBA需求的AI论文平台 千笔·专业论文写作工具 VS 知文AI
  • 2026年知名的环保板材/板材哪家强生产厂家实力参考 - 品牌宣传支持者
  • P2602 [ZJOI2010] 数字计数
  • 2026年靠谱的徽派仿古铝瓦/寺庙仿古铝瓦品牌厂家推荐哪家强 - 品牌宣传支持者
  • 2026年激光除锈机选购指南,推荐适合文物和模具除锈的靠谱品牌 - myqiye
  • 2026年眼疲劳眼液产品推荐:基于多场景实测评价,针对敏感眼与隐形眼镜佩戴痛点指南 - 品牌推荐
  • 4个颠覆维度重构无线感知技术:从隐私安全痛点到商业价值转化的实战方法论
  • 高价值立减金变现攻略:选对券、换更多、不踩坑 - 团团收购物卡回收
  • 2026年海淀海清大厦、外文文化创意园招租,这些靠谱品牌推荐给你 - mypinpai
  • 少走弯路:专科生专属的降AIGC平台,千笔·降AIGC助手 VS 灵感风暴AI
  • 在关系中划出“防火墙”:不是隔离你,而是保护咱们
  • 2026年劳保鞋工厂推荐:基于多场景实测与成本痛点深度评测排名 - 品牌推荐
  • 2026年口碑好的吸管企业推荐,涿州市荟芳塑料制品有限公司全解析 - 工业品牌热点
  • 好写作AI:学术党的“规范护卫队”,让导师少叹气,让查重不找你!
  • 云WAF与安全组的高级绕过技术
  • 洁净环境监测“守门人”:粒子计数器核心要素解析与Top5厂家推荐 - 深度智识库
  • 好写作AI:文案人的“爆款军火库”!让AI帮你批量生产100个创意标题
  • Linux音频工具keysound:自定义键盘音效的开源解决方案
  • H5GG iOS修改引擎全解析:从技术原理到实战应用
  • 全能无损音频处理工具:fre:ac让音乐转换更高效
  • wx-charts完全指南:7个核心技巧助你实现小程序数据可视化
  • 3分钟解决USB设备弹出难题:USB-Disk-Ejector工具实战指南
  • 扣子Coze实战:从0到1搭建小红书图文改写智能体
  • 微信立减金用不上?零基础变现步骤,轻松换现金 - 团团收购物卡回收
  • Android 基础入门教程4.2.3 Service精通
  • ‌量子钟在绝对零度下的运行误差分析
  • 二次元追番工具:三步打造专属番库,随时随地畅享追番乐趣
  • ROFL-Player:突破英雄联盟回放解析限制的开源工具全攻略