#3551. 逆序

传送门


给出一颗树,点带二维点权 \(w=(p,q)\)。定义 \(f(S)\) 为满足以下条件的有序对 \((x,y,z)\) 的数量:

  • \(x,y,z\) 互不相同。
  • \(a=\text{lca}(x,z),b=\text{lca}(y,z)\),有 \(w_a\) 严格偏序 \(w_b\)

\(S_0=\set{1,2,\cdots,n}\),给出 \(q\) 个询问:

  • 给出 \(x\),询问 \(f(S_0\setminus \set x)\)
  • 给出 \(x,y\),询问 \(f(S_0\setminus \set{x,y})\)

\[n,q\le 1.5\times10^5 \]


先考虑如何求出 \(f(S_0)\)

由于 \(a,b\) 均为 \(z\) 的祖先,进一步钦定 \(b\)\(a\) 的祖先,即 \(a\prec b\) 表示 \(p_a<p_b \land q_a<q_b \land \text{b 为 a 祖先}\)

alt text

由于偏序限制在 \(a,b\) 上,我们不妨钦定 \(a\)\((x,z)\) 计数方案数 \(g(a)\),钦定 \(b\)\(y\) 计数方案数 \(f(b)\)

\(s_x\)\(x\) 子树大小。

\(x,z\) 互异且 \(\text{lca}(x,z)=a\),有

\[g(a)=s_a(s_a-1)-\sum_{v\in \text{son}(s)} s_v(s_v-1) \]

\(b\)\(a\) 方向上的儿子为 \(u\),则有:

由于 \(b\) 儿子不唯一,但 \(u\) 父亲唯一,为方便维护,不妨将 \(f\) 放在 \(u\) 上维护,下文均记为 \(f(u)\)

\[f(u)=s_b-s_u \]

那么任意偏序对 \(a\prec b\) 对答案贡献 \(f(u)\cdot g(a)\)

不妨考虑三维偏序,第三维是祖先-后代限制,放在 dfs 序上即可转化为区间问题,可以 BIT 维护。

那么 cdq 即可,\(\mathcal O(n\log^2 n)\)


考虑删去一个数的情况。记删去的数为 \(c\)

不妨对所有 \(a\prec b\),记 \(G_u=\displaystyle\sum_a g(a)\)\(F_a=\displaystyle\sum_b f(u)\),均可在 cdq 过程内维护。

不难验证 \(f(S_0)=\displaystyle\sum F(a)g(a)=\sum f(u)G(u)\)

考虑删去 \(c\)\(f,g\) 的影响,记其在 \(x\) 处的影响为 \(\Delta_x\)

  • 对于 \(c\) 本身,由于 \(s'_c=s_c-1\),有 \(g'(c)=g(c)-2s'_c\),则 \(\Delta_c=2s'_cF(c)\)
  • 对于 \(c\) 的每一个祖先 \(a\),有 \(g'(a)=g(a)-2s'_a+2s'_c\),则 \(\Delta_a=2(s'_a-s'_c)F(a)\)
  • 对于 \(u\) 的父亲 \(\text{fa}_u\)\(c\) 的祖先,但 \(u\) 不是 \(c\) 的祖先,有\(f'(u)=f(u)-1\),则 \(\Delta_u=G(u)\)

上述值可以在一次 dfs 内全部预处理。


考虑删去两个数的情况。记删去的数为 \(c,d\)

不妨先将答案减去 \(\Delta_c+\Delta_d\),然后加回同时包含 \(c,d\) 的方案 \(\Delta'\)

\(t=\text{lca}(c,d)\)。 对于同时包含 \(c,d\) 的方案,有两种情况:

  • \(c,d\) 作为方案中的 \(x,z\) 出现。这种情况比较简单,有 \(\Delta'=F(t)\)
  • \(c,d\) 作为方案中的 \(x,y\) 出现:

alt text

\(t\)\(c\) 方向上的儿子为 \(u_2\)。此时对于每个 \(r\)\(c\) 的祖先但不是 \(u_2\) 的祖先,且 \(r\prec t\),记其 \(c\) 方向上的儿子为 \(u_1\),则其贡献 \(f(u_1)\) 种不同的 \(z\)

不妨差分,记 \(h(u)\)\(u\) 到根的路径上满足 \(u\prec t\)\(u\)\(f(u)\) 之和,则 \(\Delta'=h(c)-h(u_2)\)。不难在 cdq 过程中维护。

由于 \(x,y,z\) 的对称性,上面两种情况的 \(\Delta'\) 均需 \(\times 2\)

至此即可解决这个问题,仅需两次 cdq,常数较小可以拿最优解(x


#include <algorithm>
#include <iostream>
#include <vector>

const int N = 1.5e5 + 7, M = 18;
#define rep(i,a,b) for(int i(a);i<=(b);++i)
typedef long long i64;

struct node { int p, q, id; } w[N];

int n, m;
std::basic_string<int> g[N];

int st[N], ed[N], fa[N], dep[N], tim;
i64 rf[N], rg[N], xf[N], xg[N], siz[N];
int rmq[M][N], jmp[N][M];
void dfs1(int u) {
  if(fa[u]) g[u].erase(std::find(g[u].begin(), g[u].end(), fa[u]));
  st[u] = ++tim, siz[u] = 1, rmq[0][st[u]] = fa[u];
  jmp[u][0] = fa[u]; for(int j = 1; j < M; ++j) jmp[u][j] = jmp[jmp[u][j-1]][j-1];
  for(int& v: g[u]) {
    fa[v] = u, dep[v] = dep[u] + 1;
    dfs1(v);
    siz[u] += siz[v];
  }
  ed[u] = tim;
  rg[u] = siz[u] * (siz[u] - 1);
  for(int& v: g[u]) {
    rf[v] = siz[u] - siz[v];
    rg[u] -= siz[v] * (siz[v] - 1);
  }
}

inline int _min(int x, int y) { return st[x] < st[y] ? x : y; }
inline void init() {
  for(int j = 1; j < M; ++j)
    for(int i = 1<<j; i <= n; ++i)
      rmq[j][i] = _min(rmq[j-1][i], rmq[j-1][i-(1<<(j-1))]);
}
inline int lca(int x, int y) {
  if((x = st[x]) > (y = st[y])) std::swap(x, y);
  int k = std::__lg(y - x);
  return _min(rmq[k][y], rmq[k][x+(1<<k)]);
}
inline int skip(int x, int d) {
  for(int i = M-1; ~i; --i)
    if(d >> i & 1) x = jmp[x][i];
  return x;
}

struct BIT {
  i64 f[N];
  inline void _add(int x, i64 y) {
    for(; x < N; x += x & -x)
      f[x] += y;
  }
  inline void modify(int x, int y, i64 v) {
    _add(x, v), _add(y+1, -v);
  }
  inline i64 _get(int x) {
    i64 y = 0;
    for(; x; x -= x & -x)
      y += f[x];
    return y;
  }
  inline i64 query(int x, int y) {
    return _get(y) - (x ? _get(x - 1) : 0);
  }
  inline void _clear(int x) {
    for(; x < N; x += x & -x)
      f[x] = 0;
  }
  inline void clear(int x, int y) {
    _clear(x), _clear(y+1);
  }
} T;

auto Ct = [](auto&&f, auto&&...args) { f(f, args...); };
struct offq { int x, s, id; };
std::basic_string<offq> ofq[N];
i64 res[N];

inline i64 cdq() {
  std::sort(w + 1, w + n + 1, [](auto&& x, auto&& y) {
    return x.p < y.p;
  });

  i64 ans = 0;

  static node tmp[N];

  Ct([&](auto&&ptr, int l, int r) -> void {
    int mid = (l + r) >> 1;
    if(l < mid) ptr(ptr, l, mid);
    if(mid + 1 < r) ptr(ptr, mid+1, r);

    int j = l, k = mid+1, p = l;
    while(j <= mid || k <= r) {
      if(k > r || (j <= mid && w[j].q < w[k].q)) {
        int& u = w[j].id;
        for(int& v: g[u]) 
          T.modify(st[v], ed[v], rf[v]);
        tmp[p] = w[j], tmp[p++].id = j++;
      } else {
        int& u = w[k].id;
        xf[u] += T._get(st[u]);
        for(auto& [x, s, id]: ofq[u]) 
          res[id] += T._get(st[x]) - T._get(st[s]);
        tmp[p] = w[k], tmp[p++].id = k++;
      }
    }
    for(int i = l; i <= mid; ++i) 
      for(int& v: g[w[i].id]) 
        T.clear(st[v], ed[v]);

    for(int i = r; i >= l; --i) {
      int& u = w[tmp[i].id].id;
      if(tmp[i].id > mid) 
        T._add(st[u], rg[u]);
      else 
        for(int& v: g[u]) 
          xg[v] += T.query(st[v], ed[v]);
      tmp[i].id = u;
    }

    for(int i = mid+1; i <= r; ++i)
      T._clear(st[w[i].id]);

    for(int i = l; i <= r; ++i) 
      w[i] = tmp[i];
  }, 1, n);

  return ans;
}

i64 dt[N], df[N];
void dfs2(int u) {
  if(fa[u]) dt[u] += xf[fa[u]] * 2 * (siz[fa[u]] - siz[u]);
  df[u] += xf[u];
  i64 sumdf = 0;
  for(int& v: g[u]) sumdf += xg[v];
  for(int& v: g[u]) {
    dt[v] = dt[u] + (sumdf - xg[v]);
    df[v] = df[u];
    dfs2(v);
  }
  dt[u] += xf[u] * 2 * (siz[u] - 1) + sumdf;
}

std::pair<int, int> qry[N];

inline void solve() {
  std::cin >> n >> m;

  tim = 0;
  rep(i, 1, n) {
    xf[i] = xg[i] = 0;
    g[i].clear(), ofq[i].clear();
  }

  rep(i, 1, n) {
    std::cin >> w[i].p >> w[i].q, w[i].id = i;
    w[i].q = n - w[i].q + 1;
  }

  for(int t = n, x, y; --t; ) {
    std::cin >> x >> y;
    g[x] += y, g[y] += x;
  }

  dfs1(1);
  init();

  for(int i = 1; i <= m; ++i) {
    auto& [x, y] = qry[i];
    int z; std::cin >> z >> x;
    if(z == 2) {
      res[i] = 0;
      std::cin >> y;
      int f = lca(x, y);
      if(x != f) ofq[f] += {x, skip(x, dep[x] - dep[f] - 1), i};
      if(y != f) ofq[f] += {y, skip(y, dep[y] - dep[f] - 1), i};
      for(int v: {x, y}) 
        if(v != f && (w[v].p < w[f].p) == (w[v].q < w[f].q)) 
          res[i] += siz[v] - 1;
    } else y = 0;
  }

  cdq();
  rep(i, 1, n) w[i].p = n - w[i].p + 1, w[i].q = n - w[i].q + 1;
  cdq();

  i64 ans = 0;
  for(int i = 1; i <= n; ++i )
    ans += xg[i] * rf[i];
  std::cout << ans << "\n";

  dt[1] = df[1] = 0;
  dfs2(1);

  for(int i = 1; i <= m; ++i) {
    auto& [x, y] = qry[i];
    if(y) {
      res[i] += xf[lca(x, y)];
      std::cout << ans - dt[x] - dt[y] + 2 * res[i] << "\n";
    } else std::cout << ans - dt[x] << "\n";
  }
}

int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int t; std::cin >> t; while(t--) solve();
}
posted @ 2026-08-26 05:08  CuteNess  阅读(6)  评论(0)    收藏  举报