题意

有一棵 \(n\) 个节点且以 \(1\) 为根的树,把它复制成 \(m\) 个版本,有 \(q\) 次操作,每次对 \([l, r]\) 这些版本的 \(v\) 节点到根的路径收缩起来。

收缩 \(v\) 也就是把 \(v\) 到根路径上(除了根)所有点的父亲都变成根。

最后查询每个版本的每个点的 \(dep\) 之和。

数据范围

\(n, m, q \le 2 \times 10^5\)

题解

操作顺序是无所谓的,我们假设操作了点集 \(S\) ,那么最后被缩上去的点其实就是 \(\{S, root\}\) 构成虚树经过的节点。

每个点的深度其实它原来的深度减去它到根(除了根与根的儿子)被缩的点的个数。

考虑祖先对它的贡献是比较麻烦的,我们不妨考虑它对于祖先的贡献,其实就是每个深度 \(\ge 2\) 的节点的子树 \(size\) 之和。

那么我们把操作离线,只需要动态维护虚树经过所有点的权值和。

这其实是一个经典的动态虚树的问题,按照 \(dfs\) 序,用 std :: set 维护当前的点集,假设插入点为 \(k\) 找到它的前驱 \(l\) 与后继 \(r\) ,令 \(\mathrm{LCA}(l, k), \mathrm{LCA}(r, k)\) 深度较大点为 \(f\) ,那么这次新产生的路径是 \((k, f)\) 的路径(注意 \(f\) 原来就是存在于虚树中的,需要去掉),删除是类似的。

注意可能一个点被缩多次,我们需要利用 std :: multiset ,然后每次插入删除的时候查找是否还存在即可。

复杂度是 \(\mathcal O((n + q) \log n + m)\) 的。

代码

#include <bits/stdc++.h>#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endlusing namespace std;typedef long long ll;
typedef pair<int, int> PII;template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }inline int read() {int x(0), sgn(1); char ch(getchar());for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);return x * sgn;
}void File() {
#ifdef zjp_shadowfreopen ("1954.in", "r", stdin);freopen ("1954.out", "w", stdout);
#endif
}const int N = 2e5 + 1e3;vector<int> G[N];ll ans = 0, sum[N];int n, m, q, dep[N], anc[N][20], Log2[N], sz[N], dfn[N];void Dfs_Init(int u, int fa = 0) {static int clk = 0; dfn[u] = ++ clk;dep[u] = dep[anc[u][0] = fa] + 1;ans += dep[u]; sz[u] = 1;for (int v : G[u]) if (v != fa) Dfs_Init(v, u), sz[u] += sz[v];
}void Get_Sum(int u, int fa = 0) {sum[u] = sum[fa] + (dep[u] > 1) * sz[u];for (int v : G[u]) if (v != fa) Get_Sum(v, u);
}struct Cmp {inline bool operator () (const int &lhs, const int &rhs) { return dfn[lhs] < dfn[rhs]; }
};vector<int> add[N], del[N]; multiset<int, Cmp> S;inline int Lca(int x, int y) {if (dep[x] < dep[y]) swap(x, y);int gap = dep[x] - dep[y];For (i, 0, Log2[gap]) if (gap >> i & 1) x = anc[x][i];if (x == y) return x;Fordown (i, Log2[dep[x]], 0)if (anc[x][i] != anc[y][i]) x = anc[x][i], y = anc[y][i];return anc[x][0];
}int Find(int x) {PII res; auto it = S.upper_bound(x);if (it != S.end()) {int tmp = Lca(*it, x); chkmax(res, {dep[tmp], tmp});}if (it != S.begin()) {int tmp = Lca(*prev(it), x); chkmax(res, {dep[tmp], tmp});}return res.second ? res.second : x;
}int main () {File();n = read(); m = read(); q = read();For (i, 1, n - 1) {int u = read(), v = read();G[u].push_back(v); G[v].push_back(u);}while (q --) {int l = read(), r = read(), v = read();add[l].push_back(v); del[r + 1].push_back(v);}dep[0] = -1; Dfs_Init(1); Get_Sum(1);For (i, 2, n) Log2[i] = Log2[i >> 1] + 1;For (j, 1, Log2[n]) For (i, 1, n)anc[i][j] = anc[anc[i][j - 1]][j - 1];S.insert(1);For (i, 1, m) {for (int x : add[i]) {if (S.find(x) == S.end())ans -= sum[x] - sum[Find(x)];S.insert(x);}for (int x : del[i]) {S.erase(S.find(x));if (S.find(x) == S.end())ans += sum[x] - sum[Find(x)];}printf ("%lld%c", ans, i == iend ? '\n' : ' ');}return 0;}

转载于:https://www.cnblogs.com/zjp-shadow/p/10726212.html

hihoCoder #1954 : 压缩树(虚树)相关推荐

  1. [BZOJ5329][Sdoi2018]战略游戏 圆方树+虚树

    5329: [Sdoi2018]战略游戏 Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 174  Solved: 109 [Submit][Stat ...

  2. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  3. [bzoj5329][圆方树][虚树]战略游戏

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  4. [SDOI2018]战略游戏 圆方树+虚树

    Description 给T组数据. 每组数据给你一个n个点的无向图,保证图联通,给q个询问. 每个询问给k个节点,问每一次询问中,求有多少个点在断掉他之后可以使图中两个点不连通. Sample In ...

  5. 虚树-树上动态规划的利器

    虚树 问题引入 在一类树上动态规划问题中,题目给出的询问往往包含树上的很多各节点,并保证总的点数规模小于某个值. 如果我们直接在整颗树上进行 dp d p dp的话,时间复杂度与询问的次数有关,这显然 ...

  6. 数据结构专题——虚树

    虚树(virtual tree)的概念 虚树 是将一个树的点集的某一个子集,以及该子集中点的 LCALCALCA 的集合,一起所重构出来的一棵树 虚树的用途 在树型dp中,有时候没必要对整颗树进行dp ...

  7. P2495 [SDOI2011]消耗战(树形dp+虚树)

    P2495 [SDOI2011]消耗战 树形dp 状态表示:fuf_ufu​表示以uuu为根的子树中,uuu节点与子树中的关键的"隔开"所需要的最小代价 状态转移: 考虑uuu的一 ...

  8. 算法 | 虚树学习笔记

    虚树学习笔记? blog 虚树是一棵虚拟构建的树-废话 这棵树只包含关键点和关键的点,而其他不影响虚树结构的点和边都相当于进行了路径压缩-而且整棵虚树的大小不会超过关键点的2倍 举个例子? 比方说-4 ...

  9. 虚树(Kindom and its Cities,消耗战)

    模板题引入 先来看一道模板题,CF上的. 这题的意思是给定一棵有nnn个节点的树,树上有一些关键点(keykeykey).接下来有qqq组询问,每次给出kik_iki​个keykeykey,要求删去一 ...

最新文章

  1. 被遗忘的 10 个Linux命令,很实用!
  2. Ubuntu 16.04安装教程及虚拟机设置
  3. (王道408考研操作系统)第三章内存管理-第一节7:非连续分配管理方式之基本分段管理方式
  4. Linux Socket Select说明
  5. python3数据库配置,远程连接mysql服务器
  6. 【SpringBoot】SpringBoot+druid+Myibatis集成
  7. 无法复制_desktop:访问被拒绝的解决方法
  8. django学习笔记01
  9. K均值算法(K_means)
  10. Python环境与PyCharm编辑器的安装教程
  11. MT6737芯片平台处理器功能介绍资料
  12. 写一个PE的壳_Part 4:修复对ASLR支持+lief构建新PE
  13. 前端js获取图片大小 扩展名_前端获取图片存储大小的方法
  14. 1.5. 唤醒任务:TTWU(try_to_wake_up)
  15. ROS 2 Dashing Diademata安装和使用文档(含Linux、Windows和OS X)
  16. python随机生成英文字符串_如何用Python语言生成随机字符串 | 学步园
  17. ucharts Cannot read property ‘replace‘ of undefined
  18. 爬取最好大学网排名数据
  19. JS--JavaScript数据类型(数值、字符串、布尔值)详解
  20. 刷脸扫码生出种既生瑜何生亮的竞争意味

热门文章

  1. 实验23:测试泛型依赖注入★
  2. matlab的知识点1
  3. Vue el-menu高亮设置及点击菜单项实现路由跳转
  4. Grpc C# 入门
  5. Apache Solr入门教程
  6. java html字符串,java字符串方法
  7. 韩文版ie8 启用java_只有在启用了javascript的情况下,IE8才会在IE8模式下重新加载崩溃...
  8. 软件工程--第三周学习进度
  9. 【python】基础知识
  10. Java抽象类和接口