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

思路:重链剖分。

由于分了轻重儿子,我每次到重儿子的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){ //得到top
top[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);
else
return 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;
}

HDU 3966 Aragorn's Story(树链剖分)题解的更多相关文章

  1. HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树

    HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...

  2. Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)

    题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2 ...

  3. HDU 3966 Aragorn's Story(树链剖分)(线段树区间修改)

    Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问

    Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord ...

  5. HDU 3966 Aragorn's Story 树链剖分

    Link: http://acm.hdu.edu.cn/showproblem.php?pid=3966 这题注意要手动扩栈. 这题我交g++无限RE,即使手动扩栈了,但交C++就过了. #pragm ...

  6. hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询

    /** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...

  7. hdu 3966 Aragorn's Story 树链剖分 按点

    Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. HDU 3966 Aragorn's Story (树链剖分入门题)

    树上路径区间更新,单点查询. 线段树和树状数组都可以用于本题的维护. 线段树: #include<cstdio> #include<iostream> #include< ...

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

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

  10. HDU 3966 Aragorn's Story 树链拋分

    一.写在前面 终于开始开坑link-cut-tree这个了,对于网上找到的大佬的前进路线,进行了一番研发,发现实际上可以实现对于树链拋分的制作.经历了若干长时间之后终于打了出来(为什么每次学什么东西都 ...

随机推荐

  1. 1.5V升压3V集成电路升压芯片

    干电池1.5V升压3V的升压芯片,适用于干电池升压产品输出3V供电 1.5V输入时,输出3V,电流可达500MA. PW5100是一款效率大.10uA低功耗 PW5100输入电压:0.7V-5V PW ...

  2. Sklearn 与 TensorFlow 机器学习实战—一个完整的机器学习项目

    本章中,你会假装作为被一家地产公司刚刚雇佣的数据科学家,完整地学习一个案例项目.下面是主要步骤: 项目概述. 获取数据. 发现并可视化数据,发现规律. 为机器学习算法准备数据. 选择模型,进行训练. ...

  3. MYSQL面试题-索引

    MYSQL面试题-索引 引自B站up编程不良人:https://www.bilibili.com/video/BV19y4y127h4 一.什么是索引? 官方定义:索引是一种帮助mysql提高查询效率 ...

  4. pytorch——预测值转换为概率,单层感知机

    softmax函数,可以将算出来的预测值转换成0-1之间的概率形式 导数的形式 import torch import torch.nn.functional as F x=torch.tensor( ...

  5. MySQL中 utf8与utf8mb4的区别

    MySQL中 utf8与utf8mb4的区别 一.简介 ​ MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode.好在 ...

  6. logging philosophy 日志哲学

    Go kit - Frequently asked questions https://gokit.io/faq/ Logging - Why is package log so different? ...

  7. Go Concurrency Patterns: Pipelines and cancellation

    https://blog.golang.org/pipelines Go Concurrency Patterns: Pipelines and cancellation Sameer Ajmani1 ...

  8. Go Concurrency Patterns: Context At Google, we require that Go programmers pass a Context parameter as the first argument to every function on the call path between incoming and outgoing requests.

    小结: 1. Background is the root of any Context tree; it is never canceled: 2.     https://blog.golang. ...

  9. Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成,分别是依赖的关系和执行的命令 PHONY伪目标实践

    Makefile的工作流程 http://c.biancheng.net/view/7091.html Makefile文件是什么? 我们教程主要是讲的是 Makefile .很多 Linux(Uni ...

  10. Oracle数据传输MySQL中文编码问题

    最近捣鼓数据库,当使用Navicat将Oracle的数据传输给MySQL时,如果Oracle表中存在中文,则该表传输会出错,错误为: [ERR] 1366 - Incorrect string val ...