AC通道:http://acm.hdu.edu.cn/showproblem.php?pid=3966

[题目大意]

  一棵树上每个点有权值,每次支持三种操作:给[a,b]路径上的所有节点的权值加上k,给[a,b]路径上的所有节点的权值减去k,以及询问a的权值.

[分析]

  这是一道树链剖分模板题.

  树链剖分,就是将树化成了许多链,将这些链用数据结构保存起来,再去维护这个数据结构.

  假设给的树就是一条链,这道题当然很好办:直接将链用线段树存了,因为[a,b]的路径在线段树上也是连续的一段,那么修改一段就是log(n)的,询问节点也可以log(n)完成.

  但是给的是一棵树,树上两点间的路径虽然也是唯一确定的,但是在线段树上就不一定是连续的一段了.  

  于是乎,就需要一种将每条树上路径分成若干个连续段的算法.

  这就是树链剖分了.

  

  首先定义一下重儿子的概念:v是u的重儿子,当且仅当size(v)>=size(v')对于任意u的儿子v'成立.就是u的儿子中所在子树最大的儿子.

  树链剖分将树分成重链和轻边,重链指的是每个节点与其重儿子相连,其重儿子再与其重孙子相连得到的链.轻边就是连接重链的边.

  [我这儿没图....要图找别人:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 这个图其实也长得不怎么好看]

  通过这样一个划分,就有了优美的性质:任意两点间的路径上最多有log(n)条重链.

  然后就可以将重链上的点连续地存进线段树中,每次将路径划分成若干个重链的部分来处理就可以了.

  这样下来每条路径处理就是log(n)*log(n)的.

  具体步骤:

    首先一遍dfs.处理出一些东西:每个节点子树的大小->每个点的重儿子,每个点的深度[这个在划分路径的时候有用],每个节点的父节点.

    然后再一遍dfs.给每个点标号,注意将重链的编号连续,同时记录每个点所在重链的顶端节点[这个怎么操作可以具体看代码]

    然后建线段树:跟往常一样的建立方法.

    

    询问:在线段树上询问,记得下传标记就好.

    修改:思考怎么划分,如果询问的两点,假设是x,y.

    当x,y处于同一条重链时:直接用线段树的区间修改,当不是同一条重链时,就需要将他们移动到同一条重链.

    首先判断x,y所在重链,谁的上端距离根更远,假设是x,那么将x调至其所在重链的上端的父亲节点[这样就移动到了另一条重链上],同时还要将x到重链上端的这一部分在线段树中加tag.

    依次这样操作,就可以等到x,y在同一条重链上的时候了.[具体也可以看代码]

  希望通过这道题,大家也就能大概理解树链剖分的思想所在了...

  献上代码:

#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; inline int in(){
int x=,f=;char ch=getchar();
while((ch>'' || ch<'') && ch!='-') ch=getchar();
if(ch=='-') f=-,ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return x*f;
} const int maxn=; int n,m,q;
int cnt;
int a[maxn],id[maxn],Idex,rk[maxn];
int depth[maxn],sz[maxn],fa[maxn];
int top[maxn],son[maxn],head[maxn];
char ord[]; struct Spot{
int data,next;
}spot[maxn<<]; #define now spot[pt].data
#define then spot[pt].next struct Node{
int dt,tg;
}s[maxn<<]; inline void add(int u,int v){
spot[cnt].data=v;spot[cnt].next=head[u];head[u]=cnt++;
spot[cnt].data=u;spot[cnt].next=head[v];head[v]=cnt++;
} void dfs1(int x,int f){
sz[x]=,fa[x]=f;
for(int pt=head[x];pt!=-;pt=then)
if(now!=f){
depth[now]=depth[x]+;
dfs1(now,x);
sz[x]+=sz[now];
if(son[x]< || sz[now]>sz[son[x]])
son[x]=now;
}
} void dfs2(int x,int tp){
top[x]=tp,id[x]=++Idex,rk[id[x]]=x;
if(son[x]<) return;
dfs2(son[x],tp);
for(int pt=head[x];pt!=-;pt=then)
if(now!=fa[x] && now!=son[x])
dfs2(now,now);
} void build(int l,int r,int rt){
s[rt].dt=s[rt].tg=;
if(l==r){
s[rt].dt=a[rk[l]];return;
}
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
} inline void push_down(int x){
if(s[x].tg){
s[x<<].tg+=s[x].tg,s[x<<].dt+=s[x].tg;
s[x<<|].tg+=s[x].tg,s[x<<|].dt+=s[x].tg;
s[x].tg=;
}
} void add_tag(int l,int r,int x,int y,int rt,int val){
if(l==x && r==y){
s[rt].dt+=val,s[rt].tg+=val;
return;
}
int mid=(l+r)>>;
if(y<=mid) add_tag(l,mid,x,y,rt<<,val);
else if(x>mid) add_tag(mid+,r,x,y,rt<<|,val);
else add_tag(l,mid,x,mid,rt<<,val),add_tag(mid+,r,mid+,y,rt<<|,val);
} int query(int l,int r,int rt,int k){
if(l==r)
return s[rt].dt;
push_down(rt);
int mid=(l+r)>>;
if(k<=mid) return query(l,mid,rt<<,k);
else return query(mid+,r,rt<<|,k);
} void modify(int x,int y,int val){
while(top[x]!=top[y]){
if(depth[top[x]]<depth[top[y]]) swap(x,y);
add_tag(,n,id[top[x]],id[x],,val);
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
add_tag(,n,id[x],id[y],,val);
} int main(){
#ifndef ONLINE_JUDGE
freopen("3966.in","r",stdin);
freopen("3966.out","w",stdout);
#endif int u,v,x; while(~scanf("%d%d%d",&n,&m,&q)){
Idex=cnt=;
for(int i=;i<=n;i++)
a[i]=in(),head[i]=son[i]=-;
for(int i=;i<n;i++)
u=in(),v=in(),add(u,v); dfs1(,);
dfs2(,);
build(,n,); while(q--){
scanf("%s",ord);
if(ord[]=='Q'){
x=in();
printf("%d\n",query(,n,,id[x]));
}
else{
u=in(),v=in(),x=in();
if(ord[]=='D') x=-x;
modify(u,v,x);
}
}
}
return ;
}

树链剖分入门-Hdu3966 Aragorn's Story的更多相关文章

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

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

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

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

  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 树链剖分

    思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...

  5. SPOJ 375 树链剖分

    SPOJ太慢了,SPOJ太慢了, 题意:给定n(n<=10000)个节点的树,每条边有边权,有两种操作:1.修改某条变的边权:2.查询u,v之间路径上的最大边权. 分析:树链剖分入门题,看这里: ...

  6. BZOJ 4034 树链剖分

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4034 题意:中文题面 思路:树链剖分入门题. 剖分后就是一个简单的区间更新和区间求和问题. ...

  7. hdu3966 Aragorn's Story 树链剖分

    题目传送门 题目大意: 有n个兵营形成一棵树,给出q次操作,每一次操作可以使两个兵营之间的所有兵营的人数增加或者减少同一个数目,每次查询输出某一个兵营的人数. 思路: 树链剖分模板题,讲一下树链剖分过 ...

  8. HDU 3966 Aragorn's Story (树链剖分+树状数组)

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

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

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

随机推荐

  1. IE中console的正确使用方法

    本文出处原文链接 转载请注明出处 http://www.cnblogs.com/havedream/p/4519538.html 问题来源:最近在学习easyui,观看的视频教程是孙宇的<EAS ...

  2. Vue.js学习 Item13 – 指令系统与自定义指令

    基础 除了内置指令,Vue.js 也允许注册自定义指令.自定义指令提供一种机制将数据的变化映射为 DOM 行为. 可以用 Vue.directive(id, definition) 方法注册一个全局自 ...

  3. sublime几个有用的快捷键

    几个有用的快捷键:Ctrl+D:选择多个相同字符串进行修改.选中字符串,按住Ctrl+D,继续选中下一个.Ctrl+Shift+L:将选中的内容切割成多行,然后每一行可以同时编辑Ctrl+J:将已选择 ...

  4. 【原】简述使用spark集群模式运行程序

    本文前提是已经正确安装好scala,sbt以及spark了   简述将程序挂载到集群上运行的步骤: 1.构建sbt标准的项目工程结构: 其中: ~/build.sbt文件用来配置项目的基本信息(项目名 ...

  5. ng-summit and $watch() funciton

    <div ng-app> <form ng-submit="requestFunding()" ng-controller="StartUpContro ...

  6. linux下的声卡驱动架构

    1.linux下的声卡驱动架构主要分为OSS架构和ALSA架构. 2.OSS架构 OSS全称是Open Sound System,叫做开放式音频系统,这种早期的音频系统这种基于文件系统的访问方式,这意 ...

  7. Python初学者笔记:打印出斐波那契数列的前10项

    问题:斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列.费波那西数列.费波拿契数.费氏数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.- ...

  8. 编写可维护的JavaScript之简易模版

    /* * 正则替换%s * @para arg1(text) 需要替换的模版 * @para arg2 替换第一处%s * @para arg3 替换第二处%s * 返回替换后的字符串 */ var ...

  9. JavaScript高级程序设计之作用域链

    JavaScript只有函数作用域:每个函数都有个作用域链直达window对象. 变量的查找由内而外层层查找,找到即止. 同时不仅可以查找使用,甚至可以改变外部变量. var color = &quo ...

  10. 三星N8000/N8010通用刷机教程

    前面已经讲到过如何给三星n8000/n8010 Galaxy Note 10.1获取ROOT权限了.接下来就顺便告诉大家怎么给三星n8000/n8010刷机吧.其实给三星n8000/n8010刷机过程 ...