2022年01月27日,第十三天

1. 题目链接:P3384 【模板】轻重链剖分/树链剖分

思路:树链剖分直接搞,时间复杂度为 O(nlog2n)O(nlog^2n)O(nlog2n) ,通过模板题,我们可以了解到,树链剖分是用来划分树的路径的一个有效工具,它把任意两点之间的简单路径划分成 O(logn)O(log\ n)O(log n) 段线性区间,当我们得到 dfsdfsdfs 序之后套上线段树时,能够轻松地维护树上的某条链的信息。细节看代码注释。

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define re register
#define endl '\n'using namespace std;const int MOD = 998244353;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double Pi = acos(-1.0);
const int N = 1e5 + 5, M = N << 1;#define ls (x << 1)
#define rs (x << 1 | 1)int n, m, w[N], rt, P;
int h[N], e[M], ne[M], idx; // 链式前向星
int id[N], nw[N], cnt;
int dep[N]; // 当前结点的深度
int sz[N];  // 当前结点子树的大小
int top[N]; // 当前结点所在重链的最上的结点编号
int fa[N];  // 当前结点的父亲节点
int son[N]; // 当前结点的重儿子
struct Tree {int l, r;ll add, sum;
}tr[N << 2]; // 线段树信息
void add_edge (int u, int v) {e[idx] = v;ne[idx] = h[u];h[u] = idx ++;
}void dfs1 (int u, int p, int depth) {  // 用来处理重儿子dep[u] = depth, fa[u] = p, sz[u] = 1;for (int i = h[u]; ~ i; i = ne[i]) {int j = e[i];if (j == p) continue;dfs1 (j, u, depth + 1);   sz[u] += sz[j];   if (sz[son[u]] < sz[j]) son[u] = j; // 所有儿子中子树最大为重儿子}
}void dfs2 (int u, int t) { // 处理 dfs 序id[u] = ++ cnt, nw[cnt] = w[u], top[u] = t;if (! son[u]) return ;dfs2 (son[u], t);  // 重儿子的 top 是轻儿子传下来的for (int i = h[u]; ~ i; i = ne[i]) {int j = e[i];if (j == fa[u] || j == son[u]) continue;dfs2 (j, j);    // 轻儿子的 top 是自己}
}void pushup (int x) {tr[x].sum = (tr[ls].sum + tr[rs].sum) % P;
}void pushdown (int x) {Tree &p = tr[x], &lson = tr[ls], &rson = tr[rs];if (p.add) {lson.add = (p.add + lson.add) % P;lson.sum = (lson.sum + p.add * (lson.r - lson.l + 1) % P) % P;rson.add = (p.add + rson.add) % P;rson.sum = (rson.sum + p.add * (rson.r - rson.l + 1) % P) % P;p.add = 0;}
}void build (int l, int r, int x = 1) {tr[x] = {l, r, 0, nw[r]};if (l == r) return;int mid = (l + r) >> 1;build (l, mid, ls), build (mid + 1, r, rs);pushup (x);
}void update (int l, int r, int v, int x = 1) {if (l <= tr[x].l && tr[x].r <= r) {tr[x].add = (tr[x].add + v) % P;tr[x].sum = (tr[x].sum + (ll)v * (tr[x].r - tr[x].l + 1) % P) % P;return ;}pushdown (x);int mid = (tr[x].l + tr[x].r) >> 1;if (l <= mid) update (l, r, v, ls);if (r >  mid) update (l, r, v, rs);pushup (x);
}ll query (int l, int r, int x = 1) {if (l <= tr[x].l && tr[x].r <= r) return tr[x].sum;pushdown (x);int mid = (tr[x].l + tr[x].r) >> 1;ll res = 0;if (l <= mid) res += query (l, r, ls);if (r >  mid) res += query (l, r, rs);return res % P;
}void update_path (int x, int y, int v) {while (top[x] != top[y]) {if (dep[top[x]] < dep[top[y]]) swap (x, y);update (id[top[x]], id[x], v);x = fa[top[x]];}if (dep[x] < dep[y]) swap (x, y);update (id[y], id[x], v);
}ll ask_path (int x, int y) {ll res = 0;while (top[x] != top[y]) {if (dep[top[x]] < dep[top[y]]) swap (x, y);res = (res + query (id[top[x]], id[x])) % P;x = fa[top[x]];}if (dep[x] < dep[y]) swap (x, y);return (res += query (id[y], id[x])) % P;
}void update_tree (int x, int v) {update (id[x], id[x] + sz[x] - 1, v);
}ll ask_tree (int x) {return query (id[x], id[x] + sz[x] - 1);
}int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);cin >> n >> m >> rt >> P;for (int i = 1; i <= n; i ++) cin >> w[i];memset (h, -1, sizeof (h));for (int i = 1; i < n; i ++) {int u, v; cin >> u >> v;add_edge (u, v), add_edge (v, u);}dfs1 (rt, -1, 1);    // 处理重儿子dfs2 (rt, rt);      // 处理 dfs 序build (1, n);int op, x, y, z;while (m --) {cin >> op;if (op == 1) {cin >> x >> y >> z;update_path (x, y, z);}if (op == 2) {cin >> x >> y;cout << ask_path (x, y) << endl;}if (op == 3) {cin >> x >> z;update_tree (x, z);}if (op == 4) {cin >> x;cout << ask_tree (x) << endl;}}return 0;
}

2. 题目链接:P2146 [NOI2015] 软件包管理器

思路:树链剖分裸题,时间复杂度 O(nlog2n)O(nlog^2n)O(nlog2n) 。

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define re register
#define endl '\n'using namespace std;const int MOD = 998244353;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double Pi = acos(-1.0);
const int N = 1e5 + 5;int h[N], e[N], ne[N], idx;
int dep[N], sz[N], top[N], fa[N], son[N];
int id[N], cnt, n, qur;
struct node {int l, r, lazy, sum;
}t[N << 2];void add_edge (int u, int v) {e[idx] = v;ne[idx] = h[u];h[u] = idx ++;
}void dfs1 (int u, int depth) {dep[u] = depth, sz[u] = 1;for (int i = h[u]; ~ i; i = ne[i]) {int v = e[i];dfs1 (v, depth + 1);sz[u] += sz[v];if (sz[son[u]] < sz[v]) son[u] = v;}
}void dfs2 (int u, int T) {id[u] = ++ cnt, top[u] = T;if (! son[u]) return ;dfs2 (son[u], T);for (int i = h[u]; ~ i; i = ne[i]) {int v = e[i];if (v == son[u]) continue;dfs2 (v, v);}
}#define ls (x << 1)
#define rs (x << 1 | 1)void build (int l, int r, int x = 1) {t[x] = {l, r, -1, 0};if (l == r) return ;int mid = (l + r) >> 1;build (l, mid, ls), build (mid + 1, r, rs);
}void pushdown (int x) {node &p = t[x], &lson = t[ls], &rson = t[rs];if (p.lazy != -1) {lson.lazy = rson.lazy = p.lazy;lson.sum = p.lazy * (lson.r - lson.l + 1);rson.sum = p.lazy * (rson.r - rson.l + 1);p.lazy = -1;}
}void pushup (int x) {t[x].sum = t[ls].sum + t[rs].sum;
}void update (int l, int r, int v, int x = 1) {  if (l <= t[x].l && t[x].r <= r) {t[x].lazy = v;t[x].sum = v * (t[x].r - t[x].l + 1);return ;}pushdown (x);int mid = (t[x].l + t[x].r) >> 1;if (l <= mid) update (l, r, v, ls);if (r >  mid) update (l, r, v, rs);pushup (x);
}int query (int l, int r, int x = 1) {if (l <= t[x].l && t[x].r <= r) return t[x].sum;pushdown (x);int mid = (t[x].l + t[x].r) >> 1, res = 0;if (l <= mid) res += query (l, r, ls);if (r >  mid) res += query (l, r, rs);return res;
}void update_path (int v, int x, int y = 1) {while (top[x] != top[y]) {if (dep[top[x]] < dep[top[y]]) swap (x, y);update (id[top[x]], id[x], v);x = fa[top[x]];}if (dep[x] < dep[y]) swap (x, y);update (id[y], id[x], v);
}void update_tree (int x, int v) {update (id[x], id[x] + sz[x] - 1, v);
}int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);cin >> n, fa[1] = 1;memset (h, -1, sizeof (h));for (int i = 2; i <= n; i ++) {int p; cin >> p, p ++;add_edge (p, i), fa[i] = p;}dfs1 (1, 1), dfs2 (1, 1);build (1, n);cin >> qur;while (qur --) {int x; char op[20]; cin >> op >> x, x ++;if (* op == 'i') {int now = t[1].sum;update_path (1, x);cout << t[1].sum - now << endl;}else {int now = t[1].sum;update_tree (x, 0);cout << now - t[1].sum << endl;}}return 0;
}

树链剖分——轻重链剖分相关推荐

  1. 树链剖分(轻重链剖分)

    树链剖分,是一种将树剖分为链,在链上进行各种操作以达到目的的算法.树链剖分(轻重链剖分)可以解决lca(最近公共祖先),树上操作(对树上两点及经过的路的权值进行求和,修改等操作)等一类操作.对于这些问 ...

  2. 树链剖分(轻重链剖分) 讲解 (模板题目 P3384 【模板】轻重链剖分 )

    P3384 [模板]轻重链剖分 首先先说一下基本概念: 1.重儿子:一个结点的所有儿子中,大小最大的那个(最重的,所以说只有一个,如果有多个儿子的大小相等那就随便取一个). 2.轻儿子:一个结点的儿子 ...

  3. 对LCA、树上倍增、树链剖分(重链剖分长链剖分)和LCT(Link-Cut Tree)的学习

    LCA what is LCA & what can LCA do LCA(Lowest Common Ancestors),即最近公共祖先 在一棵树上,两个节点的深度最浅的公共祖先就是 L ...

  4. 树链剖分之重链剖分详解

    树链剖分之重链剖分详解 一些概念 算法讲解 应用 求最近公共祖先 对树上的一条链进行修改和查询 相关练习题 一些概念 在学习重链剖分前,首先要明白以下几个概念: 中二重儿子:就是一个节点的儿子中最&q ...

  5. P4719 【模板】“动态 DP“动态树分治(矩阵/轻重链剖分/ddp)

    P4719 [模板]"动态 DP"&动态树分治 求解树上最大权独立集,但是需要支持修改. https://www.luogu.com.cn/problem/solution ...

  6. 树链剖分(重链剖分法)

    简单的讲一下重剖. 模板题:ZJOI 2008 树的统计 + USACO 2011 Dec Gold 种草 Chapter Former 声明 在此之前,我们先声明以下定义: 重儿子:一个节点的子树大 ...

  7. 树链剖分(轻重链)入门

    写在前面 仅想学树剖LCA的同学其实不必要了解线段树 前置知识:树形结构,链式前向星(熟练),线段树(熟练),DFS序(熟练),LCA(了解定义) 树链剖分(树剖):将树分解为一条条不相交的,从祖先到 ...

  8. 树链剖分(轻重链剖+长链剖)

    Part 0 一堆废话 本来树链剖分我是不打算写帖子的,因为我一道树剖的题都没做. 后面在刷树上启发式合并的题目时刚好遇到某道到现在都没调出来的题目要码树剖,感觉这道题在敲烂警钟提醒我好好学树剖,所以 ...

  9. 树链剖分--重链剖分

    1可以将树转换成连续的数列,以此来维护树上路径之类信息 2对于每一个节点,将其子节点分为一个重节点和若干个轻节点,重节点为子树最大的节点 3定义一个轻节点一路沿着重子节点走形成的链,其余路径为轻链. ...

最新文章

  1. 探测距离机器人模型:通过超声波测距控制舵机转向,LED灯,语音播放,蜂鸣器(米思齐mixly,arduino)
  2. HDU 3200 Arborescence Counting
  3. 分析一块某宝上的WiFi摄像头模块
  4. [转]如何学好windows c++编程 学习精髓(收集,整理)
  5. 迅捷新版PDF转换器
  6. WordPress纯代码高仿 无觅相关文章 图文模式功能
  7. 如何理解最小二乘法?
  8. 科恒khs202温控器使用说明书_WS203数字显示温控器使用说明书
  9. TSW(Tencent Server Web)源码阅读指南
  10. linux 渗透 系统,初识Linux渗透:从枚举到内核利用
  11. Unity引擎光照烘焙
  12. DLL线程中坑爹的Synchronize?
  13. 大数据24小时:链家研究院发布地产大数据产品Real Data,上海交大与依图共建AI联合实验室
  14. 数据模型篇之大数据领域建模综述
  15. 砥砺前行20载,他见证了中国制造信息化的成长
  16. SuperSocket客户端
  17. 谷歌浏览器打开调试模式后刷新页面,页面一直加载问题
  18. Access学习要点1----组合框值列表原理
  19. TimerTask()定时器使用详解
  20. 大麦链接源码 大麦一键生成订单页面

热门文章

  1. 自助式BI分析有哪些优势?
  2. mongodb索引---复合索引
  3. oracle JRockit 介绍
  4. Java中实现删除左侧空格ltrim和删除右侧空格rtrim
  5. linux qc管理,QC管理选项卡
  6. jQuery中$.inArray()方法
  7. 5G课程笔记--华为ICT课堂(初学)(三)
  8. word公式编号与引用
  9. 求a+aa+aaa+aaa...a的值
  10. Zstack如何封装Windows及Linux镜像