题意:给一棵树,要求你对一个路径上的值进行加减,查询某个点的值

思路:重链剖分。

由于分了轻重儿子,我每次到重儿子的top只要O(1),经过的轻儿子最多logn条,那么我每次往上跳最多跳logn次。

所以总的路径可以分为:dfn[top[u]]到dfn[u]组成的完整路径,每次更新完走向fa[top[u]]防止重复操作。

参考:某大哥博客

代码:

#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 50000 + 5;
const int M = 50 + 5;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
int fa[maxn];   //父节点
int top[maxn];  //i所在重链的初始节点
int sz[maxn]; //i为根子树节点数
int son[maxn];    //重儿子
int deep[maxn];     //深度
int dfn[maxn], tol;  //i的dfs序编号
int fd[maxn]; //dfs序编号是i的节点int aa[maxn];
int n, m;
struct Edge{int v, next;
}edge[maxn << 1];
int head[maxn], tot;
void init(){memset(head, -1, sizeof(head));tot = tol = 0;memset(son, -1, sizeof(son));
}
void addEdge(int u, int v){edge[tot].v = v;edge[tot].next = head[u];head[u] = tot++;
}
void dfs1(int u, int pre, int d){deep[u] = d;fa[u] = pre;sz[u] = 1;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;if(v == pre) continue;dfs1(v, u, d + 1);sz[u] += sz[v];if(son[u] == -1 || sz[v] > sz[son[u]])son[u] = v;}
}
void dfs2(int u, int tp){   //得到toptop[u] = tp;dfn[u] = ++tol;fd[tol] = u;if(son[u] == -1) return;dfs2(son[u], tp);for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;if(v != son[u] && v != fa[u]){dfs2(v, v);}}
}int sum[maxn << 2], lazy[maxn << 2];
void build(int l, int r, int rt){if(l == r){sum[rt] = aa[fd[l]];lazy[rt] = 0;return;}lazy[rt] = 0;int m = (l + r) >> 1;build(l, m, rt << 1);build(m + 1, r, rt << 1 | 1);sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void pushdown(int rt, int l, int r){int m = (l + r) >> 1;if(lazy[rt]){lazy[rt << 1] += lazy[rt];lazy[rt << 1 | 1] += lazy[rt];sum[rt << 1] += lazy[rt] * (m - l + 1);sum[rt << 1 | 1] += lazy[rt] * (r - m);lazy[rt] = 0;}
}
void update(int l, int r, int L, int R, int v, int rt){if(L <= l && R >= r){lazy[rt] += v;sum[rt] += v * (r - l + 1);return;}pushdown(rt, l, r);int m = (l + r) >> 1;if(L <= m)update(l, m, L, R, v, rt << 1);if(R > m)update(m + 1, r, L, R, v, rt << 1 | 1);sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
int query(int pos, int l, int r, int rt){if(l == r){return sum[rt];}pushdown(rt, l, r);int m = (l + r) >> 1;if(pos <= m)return query(pos, l, m, rt << 1);elsereturn query(pos, m + 1, r, rt << 1 | 1);
}void add(int u, int v, int val){while(top[u] != top[v]){if(deep[top[u]] < deep[top[v]]) swap(u, v);update(1, n, dfn[top[u]], dfn[u], val, 1);u = fa[top[u]];}if(deep[u] > deep[v]) swap(u, v);update(1, n, dfn[u], dfn[v], val, 1);
}int main(){int Q;while(~scanf("%d%d%d", &n, &m, &Q)){init();for(int i = 1; i <= n; i++){scanf("%d", &aa[i]);}for(int i = 0; i < m; i++){int u, v;scanf("%d%d", &u, &v);addEdge(u, v);addEdge(v, u);}dfs1(1, -1, 0);dfs2(1, 1);build(1, n, 1);while(Q--){char o[2];int a, b, c;scanf("%s", o);if(o[0] == 'I'){scanf("%d%d%d", &a, &b, &c);add(a, b, c);}else if(o[0] == 'D'){scanf("%d%d%d", &a, &b, &c);add(a, b, -c);}else{scanf("%d", &a);printf("%d\n", query(dfn[a], 1, n, 1));}}}return 0;
}

转载于:https://www.cnblogs.com/KirinSB/p/11205336.html

HDU 3966 Aragorn's Story(树链剖分)题解相关推荐

  1. HDU - 3966 Aragorn's Story(树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一棵由n个点组成的树,每个点都有一个权值,接下来有k次操作,每次操作分为下面几种类型: I u v x:将u-v这条路径上的所有点权值加上x D u v x:将u-v ...

  2. HDU 3966 Aragorn's Story (树链点权剖分,成段修改单点查询)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 树链剖分的模版,成段更新单点查询.熟悉线段树的成段更新的话就小case啦. 1 //树链剖分 边 ...

  3. hdu 4897 Little Devil I (树链剖分+线段树)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4897 题意: 给你一棵树,一开始每条边都是白色,有三种操作: 1.将 u - v路径上的边转换颜色 ...

  4. [hdu3966 Aragorn's Story]树链剖分

    题意:要求在一棵N(<=50000)个带权节点的树上支持3种操作 (1)I u v w,u到v的路径上每个节点权值增加w (2)D u v w,u到v的路径上每个节点权值减少w (3)Q u,求 ...

  5. 洛谷3384:【模板】树链剖分——题解

    https://www.luogu.org/problemnew/show/P3384 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 ...

  6. HDU - 5242 Game(树形dp+树链剖分/树上贪心+思维)

    题目链接:点击查看 题目大意:给出一棵包含n个节点的树,每个节点都有一个权值,整棵树的根是点1,问从点1开始向下一直走到叶子节点,可以走k次,怎么样走权值和最大,每个节点被走过一次后权值会变为0 题目 ...

  7. E:Tree Queries(假树链剖分写法)

    博客园地址 E:Tree Queries 思路 当我写完A完这道题后,百度了一下,发现好像没有人是用类树链剖分来写的,都是LCALCALCA,于是我就来水一篇树链剖分题解了. 第一步:贪心取点 我们可 ...

  8. HDU - 3966 Aragorn's Story(树链剖分)

    题目传送门:HDU - 3966 Aragorn's Story 题目大意: 存在一个树,树上每个节点为一个阵营,阵营中存在敌人,现在要进行以下操作 I  C1  C2  K :将阵营C1到阵营C2路 ...

  9. HDU 3966 Aragorn's Story (树链剖分+线段树)

    题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有 ...

  10. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

最新文章

  1. hdu4280 最大流DINIC
  2. ASP.NET页面的CheckBoxList组件
  3. math标准库函数----python
  4. 关于cocopod命令
  5. linux 字符串加入中括号,Linux Shell 基础 -- 总结几种括号、引号的用法
  6. vue.js中mock本地json数据
  7. 设计模式记--Observer Pattern观察者模式
  8. ES6-set集合应用
  9. Amazon S3数据一致性模型
  10. Java并发(理论知识)—— 线程安全性
  11. 使用Dapper处理多个结果集和多重映射的教程
  12. python演化博弈仿真_基于matlab的演化博弈模型求解代码?
  13. 【测试面试题每日一刷】22道接口测试面试题,附答案
  14. vasp计算-INCAR文件
  15. SAPAS91导入期初固定资产数据往年购置与当年购置的区别
  16. dlut1216-位运算(异或)水题
  17. Excel按相同列内容合并表
  18. Golang 提取视频中音频,存为MP3格式 | Golang工具
  19. 【知识图谱】知识图谱数据构建的“硬骨头”,阿里工程师如何拿下?深度学习在知识图谱构建中的应用。
  20. PDF文件在线压缩方法

热门文章

  1. Nginx URL重写规则配置详解
  2. “梅丽莎”病毒背后的神秘黑客
  3. linux服务器磁盘陈列
  4. Zendframework 模块加载事件触发顺序。
  5. hdu 4828 Grids(拓展欧几里得+卡特兰数)
  6. 再见收费的 XShell,我改用国产良心工具,完全免费!
  7. 工作5年,别人成了架构师,你却还在基层打滚
  8. 百度统计挂了,分布式数据库异常引起,数据显示为空!
  9. 湖北经济学院计算机专业全国排名,2018年湖北经济学院世界排名、中国排名、专业排名...
  10. ssh java_java中的SSH的各自作用是什么-百度经验