【树结构】树链剖分简单分析
来源:互联网 发布:美国中文导航软件 编辑:程序博客网 时间:2024/05/21 17:50
【树结构】树链剖分
当我们需要在一棵树上完成某些区间操作,而且要求复杂度严格保持在
所谓树链剖分,就是把树分割成链,把每条链放到线段树或其他数据结构里面维护。显然,只要我们保证每次区间操作涉及的链的个数为
对于一个区间查询如“对a, b最短路径上的所有节点权值求和”,只需要用倍增处理出c = LCA(a, b)转化为对于一个节点和他祖先节点的区间求和。之后只需要不断检查c是否在当前区间内。如果在直接调用数据结构求和,如果不在则求这一区间的总和,并将节点向上推,直到depth[a] < depth[c]。
以zjoi的树的统计一题为例给出代码:
#include <bits/stdc++.h>using namespace std;const int maxm = 100005, maxn = 100005;int zkw[maxn * 4], sum[maxn * 4], N = 131072, t = 0;void update(int i, int k){ i += N - 1; zkw[i] = sum[i] = k; for (i >>= 1; i; i >>= 1) { zkw[i] = max(zkw[i << 1], zkw[(i << 1) + 1]); sum[i] = sum[i << 1] + sum[(i << 1) + 1]; }}pair<int, int> query(int i, int j){ int ans = 0, maxi = INT_MIN, p, q; for (p = i + N - 1, q = j + N - 1; p < q; p >>= 1, q >>= 1) { if (p & 1) { ans += sum[p], maxi = max(maxi, zkw[p]); p++; } if (!(q & 1)) { ans += sum[q], maxi = max(maxi, zkw[q]); q--; } } if (p == q) ans += sum[p], maxi = max(maxi, zkw[p]); return make_pair(ans, maxi);}struct node { int to, next; node() { to = next = 0; }} edge[2 * maxm];int head[maxn], top = 0;int dat[maxn], siz[maxn], id[maxn], ind[maxn], hev[maxn], dep[maxn];int father[maxn][35];int n, m;void push(int i, int j) { edge[++top].to = j; edge[top].next = head[i]; head[i] = top; }int dfs1(int i){ siz[i] = 1; for (int k = head[i]; k; k = edge[k].next) { if (!dep[edge[k].to]) { dep[edge[k].to] = dep[i] + 1; father[edge[k].to][0] = i; siz[i] += dfs1(edge[k].to); } } return siz[i];}void dfs2(int i, int from){ ind[i] = from; update(++t, dat[i]); id[i] = t; if (!head[i]) return; hev[i] = 0; for (int k = head[i]; k; k = edge[k].next) { if (dep[edge[k].to] > dep[i] && siz[edge[k].to] > siz[hev[i]]) hev[i] = edge[k].to; } if (!hev[i]) {return;} dfs2(hev[i], from); for (int k = head[i]; k; k = edge[k].next) if (dep[edge[k].to] > dep[i] && edge[k].to != hev[i]) dfs2(edge[k].to, edge[k].to);}void travel(int, int);void init(){ dep[1] = 1; memset(father, 0, sizeof father); dfs1(1); dfs2(1, 1); for (int j = 1; j <= 20; j++) for (int i = 1; i <= n; i++) father[i][j] = father[father[i][j-1]][j-1];}inline int lowbit(int i) { return i&(-i); }int lca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); int dd = dep[a] - dep[b]; while (dd) { a = father[a][(int)(log2(lowbit(dd)))]; dd -= lowbit(dd); } if (a == b) return a; for (int i = 20; i >= 0; i--) if (father[a][i] != father[b][i]) a = father[a][i], b = father[b][i]; return father[a][0];}int query_sum(int i, int j) // j is anc of i{ if (dep[i] < dep[j]) return 0; if (dep[ind[i]] <= dep[j]) return query(id[j], id[i]).first; return query_sum(father[ind[i]][0], j) + query(id[ind[i]], id[i]).first;}int query_max(int i, int j){ if (dep[i] < dep[j]) return INT_MIN; if (dep[ind[i]] <= dep[j]) return query(id[j], id[i]).second; return max(query_max(father[ind[i]][0], j), query(id[ind[i]], id[i]).second);}inline void change(int i, int j) { update(id[i], j); }inline int read() { int a; scanf("%d", &a); return a; }int main(){ memset(dep, 0, sizeof dep); memset(head, 0, sizeof head); memset(hev, 0, sizeof hev); memset(sum, 0, sizeof sum); memset(zkw, -127/3, sizeof zkw); n = read(); for (int i = 1; i < n; i++) { int a, b; a = read(); b = read(); push(a, b); push(b, a); } for (int i = 1; i <= n; i++) dat[i] = read(); init(); m = read(); char str[10]; int a, b, c; for (int i = 1; i <= m; i++) { scanf("%s", str); a = read(); b = read(); if (strcmp(str, "CHANGE") == 0) change(a, b); else if (strcmp(str, "QSUM") == 0) { c = lca(a, b); printf("%d\n", query_sum(a, c)+query_sum(b, c)-query_sum(c, c)); } else { c = lca(a, b); printf("%d\n", max(query_max(a, c), query_max(b, c))); } } return 0;}
0 0
- 【树结构】树链剖分简单分析
- Sqlite表结构简单分析
- 一个简单PDF文件的结构分析
- awdBIOS 镜像结构简单分析
- 一个简单PDF文件的结构分析
- 一个简单PDF文件的结构分析
- JAVA常用容器结构的简单分析
- SDWebImage库结构的简单分析
- 2.MFC简单的层次结构分析
- C3P0整体类结构简单分析
- C3P0整体类结构简单分析2
- iOS开发-简单的循环结构分析
- android开发中Settings结构简单分析
- ffplay.c函数结构简单分析
- Android L Settings界面结构简单分析
- C#简单程序的结构分析
- NLTK入门1:简单句子结构分析
- 比特币区块结构Merkle树及简单支付验证分析
- 在Android上使用Lambda表达式 - retrolambda插件
- 本人的嵌入式职业英文记录 - 第5周
- 欢迎使用CSDN-markdown编辑器
- 用代码生成表
- 笔记
- 【树结构】树链剖分简单分析
- 测试
- 【ISDB】【Brazil】Brazil TV Content Operators
- 关于dedecms 会员中心会员发表文章后无法更新“我的动态”方案
- 比较流行的js前端框架
- SpringBoot应用多数据源支持[嗡汤圆的小笔记]
- Unity 2D教程 | 骨骼动画:创建动画
- 个人记录-LeetCode 64. Minimum Path Sum
- python脚本整理一下桌面