CF 1844G Tree Weights

高妙题目。

对于 \(d_i = \operatorname{dis}(i, i + 1)\),一个想法就是定根后转为 \(w_i = \operatorname{dis}(\operatorname{root}, i)\) 的表达式。

不妨令 \(\operatorname{root} = 1\),那么有:

\[d_i = w_{i} + w_{i + 1} - 2w_{\operatorname{lca}(i, i + 1)} \]

看似只能尝试转为高斯消元,但是这个式子有着更好的性质,通过移项能够写做:

\[w_{i + 1} = d_i + {\color{red}2w_{\operatorname{lca}(i, i + 1)}} - w_i \]

这说明每一对 \((i, i + 1)\)\(w_i\) 都存在可递推关系,并且由于 \(w_1 = 0\),那么可以尝试递推出所有的 \(w_i\)

唯一问题是式子中含有 \(2w_{\operatorname{lca}(i, i + 1)}\),并不能保证已经递推过了,但是关注式子发现只有这一项带有常数 \(2\),于是考虑通过取模消掉常数影响

\[w_{i + 1}\equiv d_i - w_i{\color{red}\pmod 2} \]

那么就可以递推出 \(w_i \bmod 2\) 的值了。

继续,受到刚才的启发,\(2\) 这个常数相当于让我们无需考虑 \(w_{\operatorname{lca}(i, i + 1)}\) 准确值,那么尝试继续扩张 \(2\)

\[\begin{align*} &w_{i + 1}\equiv d_i + 2w_{\operatorname{lca}(i, i + 1)} - w_i\pmod 4 \\ \Longrightarrow &w_{i + 1}\equiv d_i + 2{\color{red}(w_{\operatorname{lca(i, i + 1)}}\bmod 2)} - w_i\pmod 4 \end{align*} \]

\(w_{\operatorname{lca}(i, i + 1)}\bmod 2\) 的值已经知道了,于是整个递推都能稳定进行。

通过分析上面的两个式子,发现我们能解决以下形式的递推:

\[w_{i + 1} \equiv d_i + 2(w_{\operatorname{lca}(i, i + 1)} \bmod 2^{e - 1}) - w_i\pmod {2^e} \]

因为 \(\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;
}
posted @ 2025-11-14 19:11  rizynvu  阅读(8)  评论(0)    收藏  举报