高妙题目。
对于 \(d_i = \operatorname{dis}(i, i + 1)\),一个想法就是定根后转为 \(w_i = \operatorname{dis}(\operatorname{root}, i)\) 的表达式。
不妨令 \(\operatorname{root} = 1\),那么有:
看似只能尝试转为高斯消元,但是这个式子有着更好的性质,通过移项能够写做:
这说明每一对 \((i, i + 1)\) 的 \(w_i\) 都存在可递推关系,并且由于 \(w_1 = 0\),那么可以尝试递推出所有的 \(w_i\)。
唯一问题是式子中含有 \(2w_{\operatorname{lca}(i, i + 1)}\),并不能保证已经递推过了,但是关注式子发现只有这一项带有常数 \(2\),于是考虑通过取模消掉常数影响:
那么就可以递推出 \(w_i \bmod 2\) 的值了。
继续,受到刚才的启发,\(2\) 这个常数相当于给予了我们无需考虑 \(w_{\operatorname{lca}(i, i + 1)}\) 准确值的能力,那么尝试继续扩张 \(2\):
而 \(w_{\operatorname{lca}(i, i + 1)}\bmod 2\) 的值已经知道了,于是整个递推都能稳定进行。
通过分析上面的两个式子,发现我们能解决以下形式的递推:
因为 \(\max w_i\) 是 \(\mathcal{O}(nV)\) 级别的,那么只要不断增长指数,直至当前值域包含 \(\max w_i\),若存在合法的 \(w_i\) 那一定就为当前得到的 \(w_i\),只需最后 check 合法性即可。
时间复杂度 \(\mathcal{O}(n\log (nV))\)。
#include <bits/stdc++.h>using ll = long long;constexpr int N = 1e5 + 10;int n;std::vector<std::pair<int, int>> son[N];
int dep[N], fa[N][17];
void dfs(int u) {dep[u] = dep[fa[u][0]] + 1;for (int i = 1; i < 17; i++) {fa[u][i] = fa[fa[u][i - 1]][i - 1];}for (auto [v, i] : son[u]) {if (v != fa[u][0]) {fa[v][0] = u, dfs(v);}}
}inline int lca(int x, int y) {if (dep[x] < dep[y]) {std::swap(x, y);}for (int d = dep[x] - dep[y]; d; d &= d - 1) {x = fa[x][__builtin_ctz(d)];}for (int i = 16; i >= 0; i--) {if (fa[x][i] != fa[y][i]) {x = fa[x][i], y = fa[y][i];}}return x == y ? x : fa[x][0];
}int p[N];
ll d[N], val[N], _val[N];
ll ans[N];int main() {scanf("%d", &n);for (int i = 1, x, y; i < n; i++) {scanf("%d%d", &x, &y);son[x].emplace_back(y, i);son[y].emplace_back(x, i);}dfs(1);for (int i = 2; i <= n; i++) {scanf("%lld", &d[i]), p[i] = lca(i - 1, i);}for (int i = 1; i <= 60; i++) {memcpy(_val, val, sizeof(_val));for (int j = 2; j <= n; j++) {val[j] = (_val[p[j]] * 2 + d[j] - val[j - 1] + (1ll << i)) % (1ll << i);}}for (int i = 2; i <= n; i++) {if (val[i] <= val[fa[i][0]]) {return puts("-1"), 0;}}for (int i = 2; i <= n; i++) {if (val[i - 1] + val[i] != d[i] + 2 * val[p[i]]) {return puts("-1"), 0;}}for (int i = 2; i <= n; i++) {for (auto [j, id] : son[i]) {if (j == fa[i][0]) {ans[id] = val[i] - val[j];}}}for (int i = 1; i < n; i++) {printf("%lld\n", ans[i]);}return 0;
}