Article Index

CF916E Jamie and Tree 做题笔记

Published on

题意

进行以下操作,维护树结构:

  1. 换根
  2. 查询 LCA
  3. 子树加
  4. 查询子树和

$1 \leq n, m \leq 10^5$

题解

首先你需要会 这个

这题跟 P3979 遥远的国度 唯一的区别就是要求个 LCA 嘛。

但其实你会发现这个操作毫无难度。

我们开局的时候随便选一个点把树剖了,然后看怎么应付操作。

假设当前根为 $r$。

我们记 $\mathsf{LCA}'\left(u, v\right)$ 表示以 $r$ 为根时的 LCA。$\mathsf{LCA}\left(u, v\right)$ 为以树剖时的根为根时的 LCA。

当前树中的 $\mathsf{LCA}'\left(u, v\right)$ 其实就是 $\mathsf{LCA}\left(u, v\right), \mathsf{LCA}\left(u, r\right), \mathsf{LCA}\left(v, r\right)$ 中深度最大的那个。

结论来源于分讨,喜欢讨的自己去讨。

代码

/* Please submit with C++17! It's best to use C++20 or higher version.
 * No header file and no RBLIB (https://git.rbtr.ee/root/Template).
 * By Koicy (https://koicy.ly)
 * Email n@rbtr.ee
 * I've reached the end of my fantasy.

         __    __                             __         _
   _____/ /_  / /_________  ___              / /______  (_)______  __
  / ___/ __ \/ __/ ___/ _ \/ _ \   ______   / //_/ __ \/ / ___/ / / /
 / /  / /_/ / /_/ /  /  __/  __/  /_____/  / ,< / /_/ / / /__/ /_/ /
/_/  /_.___/\__/_/   \___/\___/           /_/|_|\____/_/\___/\__, /
                               SIGN                         /___*/
#ifndef XCODE
constexpr bool _CONSOLE = false;
#else
constexpr bool _CONSOLE = true;
#endif
#define __NO_MAIN__ false
#define __ENABLE_RBLIB__ true
constexpr bool _MTS = false, SPC_MTS = false;
constexpr char EFILE[] = "";
#define FULL(arg) arg.begin(), arg.end()
#define dor(i, s, e) for (tp i = s, $##i =(s)<(e)?1:-1,$e##i=e;i!=$e##i;i+=$##i)
#define gor(i, s,e)for(tp i=s,$##i=(s)<(e)?1:-1,$e##i=(e)+$##i;i!=$e##i;i+=$##i)

// :/

signed STRUGGLING([[maybe_unused]] unsigned long TEST_NUMBER) {
  struct SEG {
    struct S {
      tp sum, len;
      
      S() = default;
      S(tp sum, tp len) : sum(sum), len(len) {}
    };
    
    static S op(S l, S r) { return S(l.sum + r.sum, l.len + r.len); }
    static S e() { return S(0, 0); }
    static S mapping(tp tag, S dat) { return S(dat.sum + tag * dat.len, dat.len); }
    static tp composition(tp tag1, tp tag2) { return tag1 + tag2; }
    static tp id() { return 0; }
  };
  tp n, m; bin >> n >> m;
  vetp a(n + 1); bin.rar(1 + FULL(a));
  vetp dep(n + 1);
  vetp f(n + 1);
  vetp hson(n + 1);
  vetp s(n + 1);
  vetp top(n + 1);
  vetp dfn(n + 1);
  vetp lst(n + 1);
  vetp real(n + 1);
  vector<vector<tp>> e(n + 1);
  for (tp i = 1; i < n; ++i) {
    tp u, v; bin >> u >> v;
    e[u].push_back(v);
    e[v].push_back(u);
  }
  lib::Segtree<SEG::S, SEG::op, SEG::e, tp, SEG::mapping, SEG::composition, SEG::id> o(n + 1);
  auto dfs1 = [&](auto $, tp x) -> void {
    dep[x] = dep[f[x]] + 1;
    s[x] = 1;
    for (auto& i : e[x]) {
      if (i == f[x]) continue;
      f[i] = x;
      $($, i);
      s[x] += s[i];
      if (s[i] > s[hson[x]]) hson[x] = i;
    }
  };
  tp cnt = 0;
  auto dfs2 = [&](auto $, tp x, tp h) -> void {
    real[lst[x] = dfn[x] = ++cnt] = x;
    top[x] = h;
    if (!hson[x]) return;
    $($, hson[x], h); lst[x] = lst[hson[x]];
    for (auto& i : e[x]) {
      if (i != f[x] && i != hson[x]) { $($, i, i); lst[x] = lst[i]; }
    }
  };
  auto LCA = [&](tp x, tp y) -> tp {
    while (top[x] != top[y]) {
      if (dep[top[x]] > dep[top[y]]) x = f[top[x]];
      else y = f[top[y]];
    }
    return dep[x] < dep[y] ? x : y;
  };
  auto get = [&](tp x, tp y) -> tp {
    while (top[x] != top[y]) {
      if (dep[top[x]] < dep[top[y]]) swap(x, y);
      if (f[top[x]] == y) return top[x];
      x = f[top[x]];
    }
    if (dep[x] > dep[y]) swap(x, y);
    return hson[x];
  };
  auto get_lca = [&](tp x, tp y, tp r) -> tp {
    tp c1 = LCA(x, y), c2 = LCA(x, r), c3 = LCA(y, r);
    if (dep[c1] >= dep[c2] && dep[c1] >= dep[c3]) return c1;
    if (dep[c2] >= dep[c1] && dep[c2] >= dep[c3]) return c2;
    return c3;
  };
  dfs1(dfs1, 1);
  dfs2(dfs2, 1, 1);
  gor(i, 1, n) o.set(dfn[i], SEG::S(a[i], 1));
  tp r = 1;
  gor(i, 1, m) {
    tp op = bin;
    if (op == 1) r = bin;
    else if (op == 2) {
      tp u, v, k; bin >> u >> v >> k;
      tp x = get_lca(u, v, r);
      if (x == r) o.apply(1, n, k);
      else if (dfn[r] > dfn[x] && dfn[r] <= lst[x]) {
        tp t = get(x, r);
        o.apply(1, dfn[t] - 1, k);
        o.apply(lst[t] + 1, n, k);
      } else o.apply(dfn[x], lst[x], k);
    } else {
      tp x = bin;
      if (x == r) bin << o.all_prod().sum << '\n';
      else if (dfn[r] > dfn[x] && dfn[r] <= lst[x]) {
        tp t = get(x, r);
        bin << o.prod(1, dfn[t] - 1).sum + o.prod(lst[t] + 1, n).sum << '\n';
      } else bin << o.prod(dfn[x], lst[x]).sum << '\n';
    }
  }
  return 0;
}

void MIST() {
}

// :\ */

No comments

Post a comment