题意:
给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
思路:
先树链剖分,然后用线段树维护一下

模板题,具体细节看代码

 const int maxn =  + ;
const int maxnode = maxn * ; int n, m, p;
//线段树部分
int add_value, qL, qR;
int addv[maxnode];
void update(int o, int L, int R)
{
if (qL <= L && R <= qR)
{
addv[o] += add_value;
}
else
{
int M = L + (R - L) / ;
if (qL <= M) update(lson);
if (qR > M) update(rson);
}
} void query(int o, int L, int R, LL add) {
if (qL <= L && R <= qR) {
printf("%d\n", add + addv[o]);
return;
}
int M = L + (R - L) / ;
if (qL <= M) query(lson, add + addv[o]);
if (qR > M) query(rson, add + addv[o]);
} //树链剖分部分:
//
//u为连接的点,w为边权
struct Edge { int v, w; };
vector<Edge> G[maxn]; //往往是双向边
void add_edge(int u, int v, int w)
{
G[u].push_back((Edge){v,w});
G[v].push_back((Edge){u,w});
} struct Node
{
int size, dep, son, top, fa, ti;
//依次表示第i个节点的:
//子节点数量,深度,所在链的顶端,重儿子,dfs序
} t[maxn]; int dfs_clock;//DFS时间序列 void dfs1(int u, int pa, int depth)//第一次DFS,得到size,dep,fa以及son的数据
{
t[u].son = ; //重儿子,为0表示没有重儿子
t[u].size = ; //节点数量
t[u].dep = depth;
t[u].fa = pa;
for (int i = ; i != G[u].size(); ++ i)
{
int v = G[u][i].v;
if (v == pa) continue;
dfs1(v, u, depth + );
t[u].size += t[v].size;
if (t[v].size > t[t[u].son].size) t[u].son = v;
}
} void dfs2(int u, int pa) // 得到时间戳等数据,u为当前节点,pa为父链顶端节点
{
t[u].ti = ++ dfs_clock; //u这个节点的时间戳是dfs_clock,dfs_clock下标是从1开始的,没有0!
t[u].top = pa; //top是u所在链的顶端
if (t[u].son != ) dfs2(t[u].son, t[u].top); //如果节点有重儿子,那么依旧是以pa为链顶端的一条链
for (int i = ; i != G[u].size(); ++ i)
{
int v = G[u][i].v;
if (v == t[u].son || v == t[u].fa) continue;//重儿子或者父节点,则跳过
dfs2(v, v);//新的一条链
}
} void lca(int x, int y)//更新x到y的之间所有的区间
{
while (t[x].top != t[y].top)
{
if (t[t[x].top].dep < t[t[y].top].dep) swap(x,y); //x深 y浅
qL=t[t[x].top].ti;
qR=t[x].ti;
update(,,n);
x = t[t[x].top].fa;
}
if (t[x].dep > t[y].dep) swap(x, y);//x是上面一些的节点
qL=t[x].ti;
qR=t[y].ti;
update(,,n);
} int value[maxn];
void init()
{
dfs_clock = ;
memset(addv, , sizeof(addv));
for (int i = ; i <= n; i++)
{
scanf("%d", value + i);
G[i].clear();
}
int u, v;
for (int i = ; i <= m; i++)
{
scanf("%d%d", &u, &v);
add_edge(u, v, );
}
} void solve()
{
dfs1(, , );
dfs2(, ); for (int i = ; i <= n; i++)
{
add_value = value[i];
qL = qR = t[i].ti;
update(, , n);
}
char op[];
int u, v, w;
while (p--)
{
scanf("%s", op);
if (op[] == 'Q')
{
scanf("%d", &u);
qL = qR = t[u].ti;
query(, , n, );
continue;
}
scanf("%d%d%d", &u, &v, &w);
if (op[] == 'D') w = -w;
add_value = w;
lca(u, v);
}
} int main()
{
while (scanf("%d%d%d", &n, &m, &p) == )
{
init();
solve();
}
return ;
}

HDU 3966 Aragorn's Story的更多相关文章

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

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

  2. hdu 3966 Aragorn&#39;s Story(树链剖分+树状数组)

    pid=3966" target="_blank" style="">题目链接:hdu 3966 Aragorn's Story 题目大意:给定 ...

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

    HDU - 3966 Aragorn's Story Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & ...

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

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

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

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

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

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

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

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

  8. HDU 3966 Aragorn&#39;s Story(树链剖分)

    HDU Aragorn's Story 题目链接 树抛入门裸题,这题是区间改动单点查询,于是套树状数组就OK了 代码: #include <cstdio> #include <cst ...

  9. hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...

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

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

随机推荐

  1. 区别ie8和ie9的方法

    众所周知 区别ie6~8的方法是: width:10px;//chrome width:10px\9;//ie8+ *width:10px;//ie7 _width:10px;//ie6 区别ie8以 ...

  2. sbrk与brk的使用小例子

    sbrk() 和 brk() - Unix的系统函数   sbrk()和brk() 系统的底层会维护一个位置,通过位置的移动完成内存的分配和回收.映射内存时 以一个内存页作为基本单位.   void* ...

  3. [必会] 表单验证+弹框~老司机原生js

    <!DOCTYPE html><html><head> <meta charset="gb2312"> <title>恰 ...

  4. JavaScript学习笔记及知识点整理_3

    1.js的事件冒泡及阻止方法:事件冒泡的概念:在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事 ...

  5. Openfire开发配置,Openfire源代码配置,OpenFire二次开发配置

    原文:http://www.cnblogs.com/lixiaolun/archive/2013/12/07/3462780.html 1.下载源代码:http://www.igniterealtim ...

  6. python的基础类源码解析——collection类

    1.计数器(counter) Counter是对字典类型的补充,用于追踪值的出现次数. ps:具备字典的所有功能 + 自己的功能 ################################### ...

  7. meta name="viewport" content="width=device-width,initial-scale=1.0" 解释

     <meta name="viewport" content="width=device-width,initial-scale=1.0">   c ...

  8. HTML基本知识

    HTML语言:超文本标记语言 基本结构: <html><head><body> <!DOCTYPE html PUBLIC "-//W3C//DTD ...

  9. row_number() OVER(PARTITION BY)函数介绍

      OVER(PARTITION BY)函数介绍 开窗函数               Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是:对于每个 ...

  10. 0506--Scrum项目1.0

    应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 团队项目选题  四则运算 NABCD 模型 1) N (Need 需求) ...