题解 ICPC 2019 SH 区域赛 F 树上简单问题
题解 ICPC 2019 SH 区域赛 F 树上简单问题
首先这个题多测非常SB, 每次都要清空, 需要特别注意.
树剖应该都会吧, Defad之后也会发博客讲解, 这里主要讲一下线段树维护区间加区间乘区间赋值区间立方和.
区间加
首先, 想一下我们要维护什么.
我们推一下式子, 看看式子中有哪些是要维护的, 哪些是要修改的.
Defad曰, "岂曰线段树题非好题乎, 岂曰推式子非神题乎, 岂曰多测出题人不满门抄斩乎".
\( (v + k)^{3} \newline = (v + k)(v + k)^{2} \newline = (v + k)(v^{2} + k^{2} + 2vk) \newline = v^{3} + k^{3} + 3v^{2}k + 3vk^{2} \)
Defad在VP时被二项式定理忘记了, 所以这里直接硬推的.
在这个式子中, 我们用到了区间立方和与区间平方和与区间和, 区间和就不用推了, 推一下区间平方和的修改.
\( (v + k)^{2} \newline = v^{2} + k^{2} + 2vk \)
我们推的是单点修改的式子, 区间修改只需在纯 \(k\) 的项上乘 \(r - l + 1\) 即可.
为什么只有纯 \(k\) 的项需要乘区间长度? 因为我们在维护 \(v\) 时已经有区间长度了, 所以只有纯 \(k\) 项需要.
区间乘
区间乘推式子其实比区间加好推, 分别乘上 \(k\) 即可.
\((vk)^{3} = v^{3}k^{3}\)
\((vk)^{2} = v^{2}k^{2}\)
\(vk = vk\)
区间赋值
区间赋值其实很好实现, 这个不需要推式子, 就是想一下, 区间乘 \(0\) 然后区间加 \(k\) 实际上就相当于区间赋值了, Defad觉得这个挺重要的建议记一下.
代码
树剖就先不给代码了, 给一下线段树的 update
和传递标记, 这里用的是动态开点线段树.
题目要求取模.
inline void pushup(int x) { t[x].val1 = (t[t[x].ls].val1 + t[t[x].rs].val1) % Mod; t[x].val2 = (t[t[x].ls].val2 + t[t[x].rs].val2) % Mod; t[x].val3 = (t[t[x].ls].val3 + t[t[x].rs].val3) % Mod; }
inline // 这个函数是结点加 f 乘 g 同时做了 void addmul(int *x, int l, int r, ll f, ll g) { if (*x == 0) *x = ++cntt; // x 没有被修改过就是空结点 if (g ^ 1LL) { // 先乘, 如果乘 1 就不用乘了 ll g2 = g * g % Mod, g3 = g2 * g % Mod; // 修改立方和 t[*x].val3 = t[*x].val3 * g3 % Mod; // 修改平方和 t[*x].val2 = t[*x].val2 * g2 % Mod; // 修改和 t[*x].val1 = t[*x].val1 * g % Mod; // 打加标记 t[*x].add = t[*x].add * g % Mod; // 打乘标记 t[*x].mul = t[*x].mul * g % Mod; } if (f ^ 0LL) { // 后加, 如果加 0 也不用加 ll f2 = f * f % Mod, f3 = f2 * f % Mod; // 修改立方和 t[*x].val3 = (t[*x].val3 + f3 * (r - l + 1) % Mod) % Mod; t[*x].val3 = (t[*x].val3 + 3LL * f2 * t[*x].val1 % Mod) % Mod; t[*x].val3 = (t[*x].val3 + 3LL * f * t[*x].val2 % Mod) % Mod; // 修改平方和 t[*x].val2 = (t[*x].val2 + f2 * (r - l + 1) % Mod) % Mod; t[*x].val2 = (t[*x].val2 + 2LL * f * t[*x].val1 % Mod) % Mod; // 修改和 t[*x].val1 = (t[*x].val1 + f * (r - l + 1) % Mod) % Mod; // 打加标记 t[*x].add = (t[*x].add + f) % Mod; } }
inline void pushdown(int x, int l, int r, int m) { // 标记下传左儿子 addmul(&t[x].ls, l, m, t[x].add, t[x].mul); // 标记下传右儿子 addmul(&t[x].rs, m + 1, r, t[x].add, t[x].mul); // 清空加标记 t[x].add = 0LL; // 清空乘标记 t[x].mul = 1LL; }
inline // 一个函数做完 + 和 * void update(int *x, int l, int r, int L, int R, ll f, ll g) { if (!*x) *x = ++cntt; if (L <= l && r <= R) { addmul(*x, l, r, f, g); } else { int m = l + r >> 1; pushdown(*x, l, r, m); if (L <= m) update(&t[*x].ls, l, m, L, R, f, g); if (m + 1 <= R) update(&t[*x].rs, m + 1, r, L, R, f, g); pushup(*x); } }
// 区间加 update(&rt, 1, N, L, R, k, 1LL); // 区间乘 update(&rt, 1, N, L, R, 0LL, k); // 区间赋值 update(&rt, 1, N, L, R, k, 0LL);
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10亿数据,如何做迁移?
· 推荐几款开源且免费的 .NET MAUI 组件库
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· c# 半导体/led行业 晶圆片WaferMap实现 map图实现入门篇
· 易语言 —— 开山篇