题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966

题意:

给出一棵树,并给定各个点权的值,然后有3种操作:

I C1 C2 K: 把C1与C2的路径上的所有点权值加上K

D C1 C2 K:把C1与C2的路径上的所有点权值减去K

Q C:查询节点编号为C的权值

分析:

典型的树链剖分,对节点进行操作,可以用树状数组或者线段树。

树链剖分+树状数组:

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring> using namespace std;
const int maxn = ; struct Edge
{
int to,next;
}edge[maxn*];
int head[maxn],cnt,num;
int a[maxn],n,m,p,c[maxn];
int size[maxn],top[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn]; void init()
{
memset(head,-,sizeof(head));
memset(son,-,sizeof(son));
memset(c,,sizeof(c));
cnt=;
num=;
}
void addedge(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
} void dfs_1(int u,int f,int d)
{
dep[u]=d;
size[u]=;
fa[u]=f;
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if(v==f)
continue;
dfs_1(v,u,d+);
size[u]+=size[v];
if(son[u]==-||size[son[u]]<size[v])
son[u]=v;
}
} void dfs_2(int u,int tp)
{
top[u] = tp;
id[u] = ++num;
if(son[u]!=-)
dfs_2(son[u],tp);
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u]||v==son[u])
continue;
dfs_2(v,v);
}
} int lowbit(int x)
{
return x&-x;
} int sum(int x)
{
int res=;
while(x>)
{
res+=c[x];
x-=lowbit(x);
}
return res;
} void add(int x,int d)
{
while(x<=n)
{
c[x]+=d;
x+=lowbit(x);
}
} void change(int u,int v,int val)
{
int tp1=top[u],tp2=top[v];
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
add(id[tp1],val);
add(id[u]+,-val);
u=fa[tp1];
tp1=top[u];
}
if(dep[u]>dep[v])
swap(u,v);
add(id[u],val);
add(id[v]+,-val);
} int main()
{
while(~scanf("%d%d%d",&n,&m,&p))
{
init();
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs_1(,,);
dfs_2(,);
for(int i=;i<=n;i++)
{
add(id[i],a[i]);
add(id[i]+,-a[i]);
}
char s[];
int c1,c2,k,c;
for(int i=;i<p;i++)
{
scanf("%s",s);
if(s[]=='I')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,k);
}
if(s[]=='D')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,-k);
}
if(s[]=='Q')
{
scanf("%d",&c);
cout<<sum(id[c])<<endl;
}
}
}
return ;
}

树链剖分+线段树:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = ;
int n,m,p;
int val[maxn],a[maxn];
struct Edge
{
int to,next;
}edge[maxn*];
int head[maxn],add[maxn*];
int dep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn];
int cnt,num;
void init()
{
memset(head,-,sizeof(head));
memset(son,-,sizeof(son));
memset(add,,sizeof(add));
cnt=;
num=;
} void addedge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
} void dfs_1(int u,int f,int d)
{
dep[u]=d;
size[u]=;
fa[u]=f;
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if(v==f)
continue;
dfs_1(v,u,d+);
size[u]+=size[v];
if(son[u]==-||size[son[u]]<size[v])
son[u]=v;
}
} void dfs_2(int u,int tp)
{
top[u] = tp;
id[u] = ++num;
if(son[u]!=-)
dfs_2(son[u],tp);
for(int i=head[u];i!=-;i=edge[i].next)
{
int v = edge[i].to;
if(v == fa[u] ||v == son[u])
continue;
dfs_2(v,v);
}
} struct Tree
{
int left,right;
int sum;
}tree[maxn*]; void pushup(int i)
{
tree[i].sum = tree[i*].sum + tree[i*+].sum;
} void build(int i,int begin,int end)
{
tree[i].left=begin;
tree[i].right=end;
if(begin==end)
{
tree[i].sum=val[begin];
return;
}
int mid=(begin+end)/;
build(i*,begin,mid);
build(i*+,mid+,end);
pushup(i);
} void pushdown(int i)
{
if(add[i])
{
add[i*] += add[i];
add[i*+] += add[i];
int mid=(tree[i].left+tree[i].right)/;
tree[i*].sum += add[i]*(mid-tree[i].left+);
tree[i*+].sum += add[i]*(tree[i].right-mid);
add[i]=;
}
} void update(int i,int begin,int end,int value)
{
if(tree[i].left>=begin&&tree[i].right<=end)
{
add[i]+=value;
tree[i].sum+=value*(tree[i].right-tree[i].left+);
return;
}
pushdown(i);
int mid=(tree[i].left+tree[i].right)/;
if(mid>=begin)
update(i*,begin,end,value);
if(mid<end)
update(i*+,begin,end,value);
pushup(i);
} void change(int u,int v,int value)
{
int tp1=top[u],tp2=top[v];
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
update(,id[tp1],id[u],value);
u = fa[tp1];
tp1 = top[u];
}
if(dep[u]>dep[v])
swap(u,v);
update(,id[u],id[v],value);
} long long query(int i,int begin,int end)
{
if(tree[i].left>=begin&&tree[i].right<=end)
return tree[i].sum;
pushdown(i);
int mid=(tree[i].left+tree[i].right)/;
long long ans=;
if(mid>=begin)
ans+=query(i*,begin,end);
if(mid<end)
ans+=query(i*+,begin,end);
return ans;
} int main()
{
while(~scanf("%d%d%d",&n,&m,&p))
{
init();
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
for(int i=;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs_1(,,);
dfs_2(,); for(int i=;i<=n;i++)
val[id[i]]=a[i];
build(,,n);
char s[];
int c1,c2,k,c;
for(int i=;i<p;i++)
{
scanf("%s",s);
if(s[]=='I')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,k);
}
if(s[]=='D')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,-k);
}
if(s[]=='Q')
{
scanf("%d",&c);
cout<<query(,id[c],id[c])<<endl;
}
}
}
return ;
}

hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)的更多相关文章

  1. Qtree3题解(树链剖分(伪)+线段树+set)

    外话:最近洛谷加了好多好题啊...原题入口 这题好像是SPOJ的题,挺不错的.看没有题解还是来一篇... 题意: 很明显吧.. 题解: 我的做法十分的暴力:树链剖分(伪)+线段树+\(set\)... ...

  2. Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)

    Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...

  3. 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

    题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...

  4. [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...

  5. 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)

    题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...

  6. 刷题总结——骑士的旅行(bzoj4336 树链剖分套权值线段树)

    题目: Description 在一片古老的土地上,有一个繁荣的文明. 这片大地几乎被森林覆盖,有N座城坐落其中.巧合的是,这N座城由恰好N-1条双 向道路连接起来,使得任意两座城都是连通的.也就是说 ...

  7. BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树

    题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...

  8. hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询

    点权树的模板题,另外发现树状数组也是可以区间更新的.. 注意在对链进行操作时方向不要搞错 线段树版本 #include<bits/stdc++.h> using namespace std ...

  9. 【BZOJ3531】[Sdoi2014]旅行 树链剖分+动态开点线段树

    [BZOJ3531][Sdoi2014]旅行 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天 ...

  10. bzoj3531——树链剖分+动态开点线段树

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MB Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连 ...

随机推荐

  1. PHP对MySQL数据库的相关操作

    一.Apache服务器的安装 <1>安装版(计算机相关专业所用软件---百度云链接下载)-直接install<2>非安装版(https://www.apachehaus.com ...

  2. Akka(15): 持久化模式:AtLeastOnceDelivery-消息保证送达模式

    消息保证送达是指消息发送方保证在任何情况下都会至少一次确定的消息送达.AtleastOnceDelivery是一个独立的trait,主要作用是对不确定已送达的消息进行补发,这是一种自动的操作,无需用户 ...

  3. WEB安全:文件上传漏洞

    文件上传漏洞过程 用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力. 一般的情况有: 上传文件WEB脚本语言,服务器的WEB容器解释并执行了用户上传的脚本,导致代码执行: ...

  4. 阿里聚安全移动安全专家分享:APP渠道推广作弊攻防那些事儿

    移动互联网高速发展,要保持APP持续并且高速增长所需的成本也越来越高.美团网CEO在今年的一次公开会议上讲到:"2017年对移动互联网公司来说是非常恐的.".主要表现在三个方面,手 ...

  5. 【jquery】ajax请求

    1. defferred对象 实现链式回调函数编程. http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_d ...

  6. 关于解决mysql数据库乱码的问题

    最近在开发的过程中频繁的使用到了mysql'这款数据库,mysql的中文乱码问题一直让人头疼.以前遇到过几次,但是都一不小心就解决了,这次终于明白到底是怎么回事了.可能我下面手的这种解决方案只适合于我 ...

  7. Docker存储

    前言 上一篇文章中简单总结了一下docke的基础使用方法,这次我来总结一下有关docker存储方面的相关知识.本文同样建立在CloudMan的系列教程之上,有兴趣的可以直接移步. 有些人可能觉得这个很 ...

  8. Android学习笔记-Button(按钮)

    Button是TextView的子类,所以TextView上很多属性也可以应用到Button 上!我们实际开发中对于Button的,无非是对按钮的几个状态做相应的操作,比如:按钮按下的时候 用一种颜色 ...

  9. 华为软件开发云对比Jenkins-JavaWeb项目持续部署方式

    一.前言:Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成和持续部署变成可能. 本文 ...

  10. wpf的一些总结

    wpf技巧 隐藏控件不占空间,设置visibility为:Collapsed tabcontrol的高度宽度跟随界面的大小变化:属性height\width绑定grid的actualheight\ac ...