Contest 10C:Ascending Tree
Contest 10C:Ascending Tree
树上保序回归。
[浅谈保序回归问题及其特殊条件下的更优替代解法](浅谈保序回归问题及其特殊条件下的更优替代解法 - Graygoo 的博客 - 洛谷博客 (luogu.com.cn))
保序回归问题,说白了就是给你一张有向图 ,并给定每个点的两个属性 ,,要求一个序列 ,满足对于图中所有有向边 ,均有 。额外给定正整数 ,要求最小化 。我们统称这类问题为 问题。
保序回归问题总共有三种解法:动态规划的维护折线优化,整体二分,网络流。
介绍第二种解法。
考虑赋值 ,转化为 的问题。
我们考虑通过整体二分逐一确定每个 的取值。
(以下参考《浅谈保序回归问题————高睿泉》)
首先有: 问题存在 全是整数的最优解。
定义原问题的 问题表示在原问题的基础上,强制要求所有 ,最小化上式的值。
那么假设 , 为原问题的一组解满足 ,那么我们通过将所有 的 变成 , 的 变成 ,也可以得到原问题的 问题的一组解。
简单证明,考虑 。
由上结论可得,我们整体二分出 ,此时显然不存在 ,于是我们考虑用一些方法对此求出 问题的一种解 ,那么 或 。
假设 对应原问题的解 。
那么若 ,则原问题中 ;否则 ,则 。
于是根据 的取值,将 分到左半段和右半段,继续二分即可。
对于本题,使用树形 dp
求出 即可,具体地,设 表示点 取 时子树的最小值,由此可求出最优方案。
时间复杂度单 log
。
以下是一些优化:
- 观察到 ,于是将一大堆
dfs
弄成拓扑序遍历。 - 观察到转移成 的问题后,答案的解 ,于是 的取值只有 种,我们整体二分的取值也只有 种,于是复杂度优化为 。
- 本质上整体二分可以队列优化的,但效果不可观。
推 [基环树上保序回归] loj 2470. 「2018 集训队互测 Day 2」有向图
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define re register
typedef long long ll;
namespace Fread {const int SIZE = 1 << 20; char buf[SIZE], *S, *T; inline char getchar() {if (S == T) {T = (S = buf) + fread(buf, 1, SIZE, stdin); if (S == T) return '\n';} return *S++;}}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#endif
inline int ri() {
re int x = 0;
re bool t = 0;
re char c = getchar();
while (c < '0' || c > '9') t |= c == '-', c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return t ? -x : x;
}
const int _ = 5e5 + 5;
int n, a[_], b[_], p[_], p1[_], p2[_], col[_], inq[_], inde, fa[_];
ll f[_][2], ans;
inline void solve(re int l, re int r, re int L, re int R) {
re int i;
if(l > r) return;
if(L == R) {
for(i = l; i <= r; ++i) ans += abs(a[p[i]] - b[L]);
return;
}
re int mid = (L + R) >> 1;
++inde;
for(i = l; i <= r; ++i) inq[p[i]] = inde, f[p[i]][0] = abs(a[p[i]] - b[mid]), f[p[i]][1] = abs(a[p[i]] - b[mid + 1]);
for(i = r; i >= l; --i) (inq[fa[p[i]]] == inde) ? (f[fa[p[i]]][0] = (f[fa[p[i]]][0] + f[p[i]][0]), f[fa[p[i]]][1] = (f[fa[p[i]]][1] + min(f[p[i]][0], f[p[i]][1]))) : 0;
re int t1 = 0, t2 = 0;
for(i = l; i <= r; ++i) col[p[i]] = (inq[fa[p[i]]] == inde && !col[fa[p[i]]]) ? (p1[++t1] = p[i], 0) : (f[p[i]][0] < f[p[i]][1] ? (p1[++t1] = p[i], 0) : (p2[++t2] = p[i], 1));
for(i = 1; i <= t1; ++i) p[l + i - 1] = p1[i];
for(i = 1; i <= t2; ++i) p[l + t1 + i - 1] = p2[i];
solve(l, l + t1 - 1, L, mid), solve(l + t1, r, mid + 1, R);
}
signed main() {
n = ri(), a[1] = ri();
re int i;
for(i = 2; i <= n; ++i) fa[i] = ri(), a[i] = ri();
for(i = 1; i <= n; ++i) {
p1[i] = p1[fa[i]] + 1, b[i] = a[i] = a[i] - (n - p1[i] + 1);
p[i] = i;
}
sort(b + 1, b + n + 1);
int tt = unique(b + 1, b + n + 1) - b - 1;
solve(1, n, 1, tt);
printf("%lld\n", ans);
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121927