首页 > 其他分享 >P4211 LCA 题解

P4211 LCA 题解

时间:2024-04-12 17:35:58浏览次数:16  
标签:int 题解 sum i64 dep dfn P4211 LCA top

前置知识:树剖、差分

题意

给定一个 \(n\) 个节点的有根树树,根为 \(1\)。有 \(m\) 个询问,每个询问给定 \(l, r, z\),求 \(\sum\limits_{i = l}^r dep[\textrm{LCA}(i, z)]\)。其中 \(dep[x]\) 表示 \(x\) 的深度,有 \(dep[1] = 1\)。

题解

式子中的 \(dep\) 不太好算,考虑转化成形式化的式子。对于单个询问 \((l, r, z)\),假设 \(a_1, a_2, \cdots, a_k\) 表示 \(1 \to z\) 路径上的点编号,显然有 \(dep[a_i] = i\);再假设 \(S_x(l, r)\) 表示 \(x\) 子树内编号在 \([l, r]\) 中的点数量,那么:

\[\begin{aligned} &\sum\limits_{i = l}^r dep[\textrm{LCA}(i, z)]\\ =& k \times S_{a_k}(l, r) + \sum\limits_{i = 1}^{k - 1} i \times (S_{a_i}(l, r) - S_{a_{i + 1}}(l, r)) \\ \end{aligned} \]

将每个 \(S_{a_i}(l, r)\) 的系数化简一下,得到:

\[\begin{aligned} &k \times S_{a_k}(l, r) + \sum\limits_{i = 1}^{k - 1} i \times (S_{a_i}(l, r) - S_{a_{i + 1}}(l, r)) \\ =&\sum\limits_{i = 1}^k S_{a_i}(l, r) \end{aligned} \]

这个式子不太能直接做,差分一下,得到:

\[\begin{aligned} &\sum\limits_{i = 1}^k S_{a_i}(l, r)\\ =&\sum\limits_{i = 1}^k \left(S_{a_i}(1, r) - S_{a_i}(1, l - 1)\right) \end{aligned} \]

接着考虑计算一个前缀的答案,将询问离线下来,然后从 \(1\) 到 \(n\) 一个一个插入。对于 \(i\),可以发现 \(i\) 的出现只会对 \(1 \to i\) 这条链上的点的 \(S\) 产生影响,所以直接链加。而查询的时候,直接查询链和即可。这两个东西可以树剖做。复杂度 \(O(n \log^2 n)\)。

code:

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 5E4 + 5;
int n, m, son[N], tot, dfn[N], sz[N], top[N], yf[N], dep[N], wt[N];
i64 Ans[N];
vector <tuple <int, int, int>> v[N];
vector <int> G[N];
void dfs1(int x, int fa) {
  sz[x] = 1; pair <int, int> mx = make_pair(0, 0);
  for (auto v : G[x]) {
    if (v == fa) continue;
    dep[v] = dep[x] + 1; yf[v] = x;
    dfs1(v, x);
    sz[x] += sz[v];
    mx = max(mx, make_pair(sz[v], v));
  } son[x] = mx.second;
}
void dfs2(int x, int topf) {
  wt[dfn[x] = ++tot] = x; top[x] = topf;
  if (!son[x]) return ;
  dfs2(son[x], topf);
  for (auto v : G[x]) {
    if (v == yf[x] || v == son[x]) continue ;
    dfs2(v, v);
  }
}
struct segt {
  struct node {
    int l, r;
    i64 sum, tag;
  } t[N << 2];
  int lson(int x) {return x << 1;}
  int rson(int x) {return x << 1 | 1;}
  void pushup(int x) {t[x].sum = t[lson(x)].sum + t[rson(x)].sum;}
  void build(int x, int l, int r) {
    t[x].l = l; t[x].r = r; t[x].tag = t[x].sum = 0;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    build(lson(x), l, mid); 
    build(rson(x), mid + 1, r);
    pushup(x);  
  }
  void upd(int x, i64 val) {t[x].tag += val; t[x].sum += val * (t[x].r - t[x].l + 1);}
  void pushdown(int x) {
    upd(lson(x), t[x].tag); upd(rson(x), t[x].tag);
    t[x].tag = 0;
  }
  void update(int x, int L, int R) {
    if (t[x].l >= L && t[x].r <= R) return upd(x, 1);
    int mid = (t[x].l + t[x].r) >> 1; pushdown(x);
    if (L <= mid) update(lson(x), L, R);
    if (R > mid) update(rson(x), L, R);
    pushup(x);
  }
  i64 query(int x, int L, int R) {
    if (t[x].l >= L && t[x].r <= R) return t[x].sum;
    int mid = (t[x].l + t[x].r) >> 1; i64 res = 0; pushdown(x);
    if (L <= mid) res += query(lson(x), L, R);
    if (R > mid) res += query(rson(x), L, R);
    return res;
  }
} t;
void update(int x) {
  while (top[x] != 1) {
    t.update(1, dfn[top[x]], dfn[x]);
    x = yf[top[x]];
  }
  t.update(1, 1, dfn[x]);
}
i64 query(int x) {
  i64 res = 0;
  while (top[x] != 1) {
    res += t.query(1, dfn[top[x]], dfn[x]);
    x = yf[top[x]];
  } return res + t.query(1, 1, dfn[x]);
}
signed main(void) {
  ios :: sync_with_stdio(false);
  cin.tie(0); cout.tie(0);
  cin >> n >> m;
  for (int i = 2; i <= n; ++i) {
    int p; cin >> p; ++p;
    G[i].emplace_back(p);
    G[p].emplace_back(i);
  } dep[1] = 1;
  dfs1(1, 0); dfs2(1, 1); t.build(1, 1, n);
  for (int i = 1; i <= m; ++i) {
    int l, r, z; cin >> l >> r >> z;
    ++z; ++l, ++r;
    v[r].emplace_back(1, i, z);
    v[l - 1].emplace_back(-1, i, z);
  }
  for (int i = 1; i <= n; ++i) {
    update(i);
    for (auto [val, id, x] : v[i]) 
      Ans[id] += val * query(x);
  }
  for (int i = 1; i <= m; ++i) 
    cout << Ans[i] % 201314 << '\n';
  return 0;
}

标签:int,题解,sum,i64,dep,dfn,P4211,LCA,top
From: https://www.cnblogs.com/CTHOOH/p/18090205

相关文章

  • [题解] [NOIP2011] 聪明的质检员
    [NOIP2011]聪明的质监员题目描述小T是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有\(n\)个矿石,从\(1\)到\(n\)逐一编号,每个矿石都有自己的重量\(w_i\)以及价值\(v_i\)。检验矿产的流程是:给定\(m\)个区间\([l_i,r_i]\);选出一个参数\(W\);对......
  • Qt程序加载Qt platform plugin 'xcb' 出错问题解决
    1.Qt程序运行环境ubuntu16.04Qt5.12.3Qt可执行程序编译后运行Qt可执行程序后出现报错报错内容:qt.qpa.plugin:CouldnotloadtheQtplatformplugin"xcb"in""eventhoughitwasfound.ThisapplicationfailedtostartbecausenoQtplatformplugincouldbe......
  • [题解][2022江西省程序设计竞赛] Graphic Game
    题目描述Cirno被推荐了一个游戏,她决定今天和大妖精一起玩。最初,有一个包含2×n个顶点和m条边的图。在每一轮中,Cirno和大妖精都必须选择一个不同的顶点。所选顶点的度数必须相同。然后,Cirno和大妖精将从图中移除它们。现在Cirno想知道是否有办法从给定的图中移除所有顶点。如果......
  • windows MySQL报错Packet for query is too large问题解决
    1、报错Cause:com.mysql.cj.jdbc.exceptions.PacketTooBigException:Packetforqueryistoolarge(11,792,709>4,194,304).Youcanchangethisvalueontheserverbysettingthe'max_allowed_packet'variable.出现问题的原因:批量插入数据量过大MySQL根据配置......
  • [学习笔记] LCA - 图论
    [NOIP2013提高组]货车运输最大生成树+LCA+倍增好家伙,这道题我写了一个晚上,调了两个晚上,对于这道题我颇有感触。但这道题确实好,实实在在的蓝题,让我发现了许多关于LCA的问题。首先,这个题给的是一个无向图,并不是个树,为了减少运算量,我们可以把它变成一个树。运用Kruskal算法生......
  • Cunning Gena 题解
    \(\texttt{ProblemLink}\)简要题意翻译很清楚。思路记\(x_i\)表示第\(i\)个人的花费,\(s_i\)表示第\(i\)个人做题集合,\(k_i\)表示第\(i\)个人需要的显示器。\(m\le20\)且不是计数,考虑dp,发现确实可以做。可以设\(f_i\)表示做题集合为\(i\)时最小花费。易......
  • [题解][2022江西省程序设计大赛] A Game of Taking Numbers
    题目描述rqdmap和他的小女友正在玩一个游戏。有n个正整数。这两个人轮流取数字。为了显示他的绅士风度,rqdmap要求他的小女友先取数字。每当rqdmap的小女友可以选择剩下的数字中的任意一个来拿走(记为x),rqdmap需要从剩下的数字中选择一个数字(记为y),并且满足以下两个条件中的至少一个......
  • 文件下载时中文文件名乱码及链接失效问题解决
    问题:报错提示11-Apr-202415:38:43.792信息[Catalina-utility-2]org.apache.catalina.startup.HostConfig.deployDirectoryWeb应用程序目录[G:\开发工作用软件\Java开发用\apache-tomcat-10.1.7\webapps\manager]的部署已在[293]毫秒内完成11-Apr-202415:38:44.573信息......
  • 题解 P10314【[SHUPC 2024] 函数】
    注意到:\[f(x)=\lfloorx\rfloor,\qquad(x\notin\N)\]代码:intT;doublex;cout<<fixed<<setprecision(12);for(cin>>T;T;--T){cin>>x;cout<<floor(x)<<endl;}感觉说明不够过不了审,于是简单说一下正确性:由诱导公式\(\c......
  • [题解] [洛谷P1404] 平均数
    洛谷P1404平均数题目描述给一个长度为\(n\)的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度\(\geqm\)。输入格式第一行两个整数\(n\)和\(m\)。接下来\(n\)行,每行一个整数\(a_i\),表示序列第\(i\)个数字。输出格式一个整数,表示最大平均数......