CF1844G Tree Weights
给你一颗边权未知的树和一个数组 \(f\),表示对于每个 \(i\),点 \(i\) 到 \(i+1\) 的距离。
你要尝试还原树的边权。
钦定点 \(1\) 为根,我们考虑树上两个点的距离公式
\[dist(x,y) = d_x + d_y - 2d_{lca(x,y)}
\]
\(d_i\) 表示点 \(i\) 的深度
然后我们记 \(p_i=lca(i,i+1)\),那么不难得到
\[d_{i+1} = f_i - d_i + 2d_{p_i}
\]
到了这里我们直接高斯消元就可以 \(O(n^3)\) 做了。
考虑是什么阻止了我们直接递推求值,原因就是不一定 \(p_i \le i\)。
这样我们无法在计算 \(d_{i+1}\) 之前得到 \(d_{p_i}\) 的值。
然后这道题最神奇的地方就来了,我们发现转移式里面 \(d_{p_i}\) 带有一个 \(2\) 的系数。
这意味着我们只需要 \(d_{p_i}\) 在二进制下前 \(k\) 位的值就可以递推得到 \(d_{i+1}\) 第 \(k+1\) 位的值。
因此我们可以先确定所有 \(d_i \bmod 2\) 的值,然后就可以确定所有 \(d_i \bmod 4\) 的值,依次倍增这道题就做完了。
#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
using std::cin, std::cout;
const int N = 2e5 + 7;
typedef long long i64;
int dt[N], fa[N];
std::vector<std::pair<int, int>> g[N];
class LCAcalculator {
private:
static const int M = std::__lg(N) + 1;
int dp[M][N], *eu = dp[0], ti[N], de[N], id, lg[N];
void dfs(int u=1, int f=0) {
eu[ti[u] = ++id] = u, fa[u] = f, de[u] = de[f] + 1;
for(auto& [v, z]: g[u]) if(v != f) {
dfs(v, u), dt[v] = z, eu[++id] = u;
}
}
inline int _min(int x, int y) {
return de[x] < de[y] ? x : y;
}
public:
void init() {
dfs(1, 0);
for(int j = 1; j < M; ++j) {
int t = (1 << (j - 1));
for(int i = (1 << j); i <= id; ++i) {
dp[j][i] = _min(dp[j-1][i], dp[j-1][i-t]);
}
}
lg[1] = 0;
for(int i = 2; i <= id; ++i)
lg[i] = lg[i >> 1] + 1;
}
inline int query(int x, int y) {
x = ti[x], y = ti[y]; if(x > y) std::swap(x, y);
int k = lg[y - x + 1];
return _min(dp[k][y], dp[k][x + (1 << k) - 1]);
}
} __lca__;
int n, lca[N];
i64 ans[N], dist[N], deep[N];
int main() {
cin >> n;
for(int i = 1, x, y; i < n; ++i)
cin >> x >> y, g[x].emplace_back(y, i), g[y].emplace_back(x, i);
__lca__.init();
for(int i = 1; i < n; ++i)
lca[i] = __lca__.query(i, i + 1);
for(int i = 1; i < n; ++i) cin >> dist[i];
for(int k = 0; k < 61; ++k) {
i64 mask = (1ll << k) - 1;
for(int i = 1; i < n; ++i) {
i64 vl = (dist[i] & mask) + (deep[lca[i]] << 1);
deep[i + 1] = (vl + mask + 1 - deep[i]) & mask;
}
}
for(int i = 2; i <= n; ++i) {
if(deep[i] <= deep[fa[i]])
cout << "-1\n", exit(0);
ans[dt[i]] = deep[i] - deep[fa[i]];
}
for(int i = 1; i < n; ++i)
if(deep[i] + deep[i + 1] - 2 * deep[lca[i]] != dist[i])
cout << "-1\n", exit(0);
for(int i = 1; i < n; ++i)
cout << ans[i] << "\n";
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/18719670

浙公网安备 33010602011771号