题目链接: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的权值

分析:

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

树链剖分+树状数组:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstring>
  5.  
  6. using namespace std;
  7. const int maxn = ;
  8.  
  9. struct Edge
  10. {
  11. int to,next;
  12. }edge[maxn*];
  13. int head[maxn],cnt,num;
  14. int a[maxn],n,m,p,c[maxn];
  15. int size[maxn],top[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn];
  16.  
  17. void init()
  18. {
  19. memset(head,-,sizeof(head));
  20. memset(son,-,sizeof(son));
  21. memset(c,,sizeof(c));
  22. cnt=;
  23. num=;
  24. }
  25. void addedge(int u,int v)
  26. {
  27. edge[cnt].to = v;
  28. edge[cnt].next = head[u];
  29. head[u] = cnt++;
  30. }
  31.  
  32. void dfs_1(int u,int f,int d)
  33. {
  34. dep[u]=d;
  35. size[u]=;
  36. fa[u]=f;
  37. for(int i=head[u];i!=-;i=edge[i].next)
  38. {
  39. int v=edge[i].to;
  40. if(v==f)
  41. continue;
  42. dfs_1(v,u,d+);
  43. size[u]+=size[v];
  44. if(son[u]==-||size[son[u]]<size[v])
  45. son[u]=v;
  46. }
  47. }
  48.  
  49. void dfs_2(int u,int tp)
  50. {
  51. top[u] = tp;
  52. id[u] = ++num;
  53. if(son[u]!=-)
  54. dfs_2(son[u],tp);
  55. for(int i=head[u];i!=-;i=edge[i].next)
  56. {
  57. int v=edge[i].to;
  58. if(v==fa[u]||v==son[u])
  59. continue;
  60. dfs_2(v,v);
  61. }
  62. }
  63.  
  64. int lowbit(int x)
  65. {
  66. return x&-x;
  67. }
  68.  
  69. int sum(int x)
  70. {
  71. int res=;
  72. while(x>)
  73. {
  74. res+=c[x];
  75. x-=lowbit(x);
  76. }
  77. return res;
  78. }
  79.  
  80. void add(int x,int d)
  81. {
  82. while(x<=n)
  83. {
  84. c[x]+=d;
  85. x+=lowbit(x);
  86. }
  87. }
  88.  
  89. void change(int u,int v,int val)
  90. {
  91. int tp1=top[u],tp2=top[v];
  92. while(tp1!=tp2)
  93. {
  94. if(dep[tp1]<dep[tp2])
  95. {
  96. swap(tp1,tp2);
  97. swap(u,v);
  98. }
  99. add(id[tp1],val);
  100. add(id[u]+,-val);
  101. u=fa[tp1];
  102. tp1=top[u];
  103. }
  104. if(dep[u]>dep[v])
  105. swap(u,v);
  106. add(id[u],val);
  107. add(id[v]+,-val);
  108. }
  109.  
  110. int main()
  111. {
  112. while(~scanf("%d%d%d",&n,&m,&p))
  113. {
  114. init();
  115. for(int i=;i<=n;i++)
  116. scanf("%d",&a[i]);
  117. for(int i=;i<=m;i++)
  118. {
  119. int u,v;
  120. scanf("%d%d",&u,&v);
  121. addedge(u,v);
  122. addedge(v,u);
  123. }
  124. dfs_1(,,);
  125. dfs_2(,);
  126. for(int i=;i<=n;i++)
  127. {
  128. add(id[i],a[i]);
  129. add(id[i]+,-a[i]);
  130. }
  131. char s[];
  132. int c1,c2,k,c;
  133. for(int i=;i<p;i++)
  134. {
  135. scanf("%s",s);
  136. if(s[]=='I')
  137. {
  138. scanf("%d%d%d",&c1,&c2,&k);
  139. change(c1,c2,k);
  140. }
  141. if(s[]=='D')
  142. {
  143. scanf("%d%d%d",&c1,&c2,&k);
  144. change(c1,c2,-k);
  145. }
  146. if(s[]=='Q')
  147. {
  148. scanf("%d",&c);
  149. cout<<sum(id[c])<<endl;
  150. }
  151. }
  152. }
  153. return ;
  154. }

树链剖分+线段树:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. using namespace std;
  6. const int maxn = ;
  7. int n,m,p;
  8. int val[maxn],a[maxn];
  9. struct Edge
  10. {
  11. int to,next;
  12. }edge[maxn*];
  13. int head[maxn],add[maxn*];
  14. int dep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn];
  15. int cnt,num;
  16. void init()
  17. {
  18. memset(head,-,sizeof(head));
  19. memset(son,-,sizeof(son));
  20. memset(add,,sizeof(add));
  21. cnt=;
  22. num=;
  23. }
  24.  
  25. void addedge(int u,int v)
  26. {
  27. edge[cnt].to=v;
  28. edge[cnt].next=head[u];
  29. head[u]=cnt++;
  30. }
  31.  
  32. void dfs_1(int u,int f,int d)
  33. {
  34. dep[u]=d;
  35. size[u]=;
  36. fa[u]=f;
  37. for(int i=head[u];i!=-;i=edge[i].next)
  38. {
  39. int v=edge[i].to;
  40. if(v==f)
  41. continue;
  42. dfs_1(v,u,d+);
  43. size[u]+=size[v];
  44. if(son[u]==-||size[son[u]]<size[v])
  45. son[u]=v;
  46. }
  47. }
  48.  
  49. void dfs_2(int u,int tp)
  50. {
  51. top[u] = tp;
  52. id[u] = ++num;
  53. if(son[u]!=-)
  54. dfs_2(son[u],tp);
  55. for(int i=head[u];i!=-;i=edge[i].next)
  56. {
  57. int v = edge[i].to;
  58. if(v == fa[u] ||v == son[u])
  59. continue;
  60. dfs_2(v,v);
  61. }
  62. }
  63.  
  64. struct Tree
  65. {
  66. int left,right;
  67. int sum;
  68. }tree[maxn*];
  69.  
  70. void pushup(int i)
  71. {
  72. tree[i].sum = tree[i*].sum + tree[i*+].sum;
  73. }
  74.  
  75. void build(int i,int begin,int end)
  76. {
  77. tree[i].left=begin;
  78. tree[i].right=end;
  79. if(begin==end)
  80. {
  81. tree[i].sum=val[begin];
  82. return;
  83. }
  84. int mid=(begin+end)/;
  85. build(i*,begin,mid);
  86. build(i*+,mid+,end);
  87. pushup(i);
  88. }
  89.  
  90. void pushdown(int i)
  91. {
  92. if(add[i])
  93. {
  94. add[i*] += add[i];
  95. add[i*+] += add[i];
  96. int mid=(tree[i].left+tree[i].right)/;
  97. tree[i*].sum += add[i]*(mid-tree[i].left+);
  98. tree[i*+].sum += add[i]*(tree[i].right-mid);
  99. add[i]=;
  100. }
  101. }
  102.  
  103. void update(int i,int begin,int end,int value)
  104. {
  105. if(tree[i].left>=begin&&tree[i].right<=end)
  106. {
  107. add[i]+=value;
  108. tree[i].sum+=value*(tree[i].right-tree[i].left+);
  109. return;
  110. }
  111. pushdown(i);
  112. int mid=(tree[i].left+tree[i].right)/;
  113. if(mid>=begin)
  114. update(i*,begin,end,value);
  115. if(mid<end)
  116. update(i*+,begin,end,value);
  117. pushup(i);
  118. }
  119.  
  120. void change(int u,int v,int value)
  121. {
  122. int tp1=top[u],tp2=top[v];
  123. while(tp1!=tp2)
  124. {
  125. if(dep[tp1]<dep[tp2])
  126. {
  127. swap(tp1,tp2);
  128. swap(u,v);
  129. }
  130. update(,id[tp1],id[u],value);
  131. u = fa[tp1];
  132. tp1 = top[u];
  133. }
  134. if(dep[u]>dep[v])
  135. swap(u,v);
  136. update(,id[u],id[v],value);
  137. }
  138.  
  139. long long query(int i,int begin,int end)
  140. {
  141. if(tree[i].left>=begin&&tree[i].right<=end)
  142. return tree[i].sum;
  143. pushdown(i);
  144. int mid=(tree[i].left+tree[i].right)/;
  145. long long ans=;
  146. if(mid>=begin)
  147. ans+=query(i*,begin,end);
  148. if(mid<end)
  149. ans+=query(i*+,begin,end);
  150. return ans;
  151. }
  152.  
  153. int main()
  154. {
  155. while(~scanf("%d%d%d",&n,&m,&p))
  156. {
  157. init();
  158. for(int i=;i<=n;i++)
  159. scanf("%d",&a[i]);
  160. for(int i=;i<=m;i++)
  161. {
  162. int u,v;
  163. scanf("%d%d",&u,&v);
  164. addedge(u,v);
  165. addedge(v,u);
  166. }
  167. dfs_1(,,);
  168. dfs_2(,);
  169.  
  170. for(int i=;i<=n;i++)
  171. val[id[i]]=a[i];
  172. build(,,n);
  173. char s[];
  174. int c1,c2,k,c;
  175. for(int i=;i<p;i++)
  176. {
  177. scanf("%s",s);
  178. if(s[]=='I')
  179. {
  180. scanf("%d%d%d",&c1,&c2,&k);
  181. change(c1,c2,k);
  182. }
  183. if(s[]=='D')
  184. {
  185. scanf("%d%d%d",&c1,&c2,&k);
  186. change(c1,c2,-k);
  187. }
  188. if(s[]=='Q')
  189. {
  190. scanf("%d",&c);
  191. cout<<query(,id[c],id[c])<<endl;
  192. }
  193. }
  194. }
  195. return ;
  196. }

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. Effective Objective-C 2.0 Tips 总结 Chapter 3 & Chapter 4

    Chapter 3 接口与 API 设计 Tips 15 使用前缀避免明明空间冲突 Objective-C 没有命名空间,所以我们在起名时要设法避免命名冲突 避免命名冲突的方法就是使用前缀 应用中的所 ...

  2. 关于移动端自动化测试-Appium的搭建

    web端我们常用的开源自动化用的是selenium,而移动端我们选择的是Appium,当然也可以使用monkey或者阿里的macaca,他们在理论上都使用了webdriver: 关于Appium环境的 ...

  3. Angular02 将数据添加到组件中

    准备:已经搭建好angular-cli环境.知道如何创建组件 一.将一个数据添加到组件中 1 创建一个新的组件 user-item 2 将组件添加到静态模板中 3 为组件添加属性,并利用构造器赋值 4 ...

  4. (转)CentOS6.5下Redis安装与配置

    场景:项目开发中需要用到redis,之前自己对于缓存这块一直不是很理解,所以一直有从头做起的想法. 本文详细介绍redis单机单实例安装与配置,服务及开机自启动.如有不对的地方,欢迎大家拍砖o(∩_∩ ...

  5. (转)Windows7下命令行使用MySQL

    1 安装 我在Win7下安装的MySQL版本是mysql-5.0.22-win32 1.在Win7环境下安装MySQL,关于安装方法可以参考文章: Win7系统安装MySQL5.5.21图解教程.wi ...

  6. Spring源码情操陶冶-ContextLoader

    前言-阅读源码有利于陶冶情操,本文承接前文Spring源码情操陶冶-ContextLoaderListener 静态代码块内容 ContextLoader在被主动调用的时候,会执行其的一个静态块,代码 ...

  7. 前端javascript中字符串的总结

    1.截取方法 截取字符串的abcdefg中的efg. 注意:str.length从1的开始数 var str="abcdefg"; (1).slice() : console.lo ...

  8. 解决div里面img的缝隙问题(转)

    图片IMG与容器下边界之间有空隙怎么办?这里介绍3中简单的解决方法. 第一,给图片img标签display:block. img{display:block} 第二,定义容器里的字体大小为0. div ...

  9. vue中watched属性

    watched属性,vue中的观察属性,可用来监听一个值的变化 默认有两个参数,新值,旧值 data (){ return { currentCity: "深圳" } } watc ...

  10. Mybatis 的分页条件查询语句编写

    刚来到一家新公司, 翻看项目代码, 发现一位同事写的查询逻辑很好, 不用插件, 一个语句完成了分页条件查询. 而我之前一般都是在业务层对参数进行判断, 如果有条件,就调用条件查询的方法, 如果没有条件 ...