Snacks HDU 5692 dfs序列+线段树

题意

百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。

由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。

为小度熊规划一个路线,使得路线上的价值总和最大

输入输出:

输入数据第一行是一个整数T(T≤10),表示有T组测试数据。

对于每组数据,包含两个整数n,m(1≤n,m≤100000),表示有n个零食机,m次操作。

接下来n−1行,每行两个整数x和y(0≤x,y<n),表示编号为x的零食机与编号为y的零食机相连。

接下来一行由n个数组成,表示从编号为0到编号为n−1的零食机的初始价值v(|v|<100000)。

接下来m行,有两种操作:0 x y,表示编号为x的零食机的价值变为y;1 x,表示询问从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。

本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上:

  1. #pragma comment(linker, "/STACK:1024000000,1024000000")

题解思路

dfs序列的题,这是第一道,当然不出意外,我不会做。但是我找到一篇写的非常好的博客,详细解释了这个题。点我链接

思路就是用dfs序列,将树“拍”成一维的一串,这样就可以用线段树或者树状数组进行接下来的操作了。

至于为什么要转化为一维的,因为简单啊,并且用来处理一维数据的方法也很多。

代码实现

两种形似,第一个是数组形式的线段树,有注释。第二种是使用结构体线段树,和第一种基本一样。

  1. #pragma comment(linker, "/STACK:1024000000,1024000000")
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <vector>
  5. #include <iostream>
  6. using namespace std;
  7. vector <int> a[100001];
  8. int n,m,now = 0,b[100001],xulie[100005],e[100005];
  9. long long v[100005],dis[100005] ={0},maxsum[100005*4],lazy_tag[100005*4] = {0};
  10. void dfs(int x,int pre)//深搜找dfs序
  11. {
  12. b[x] = ++now;//这是这个节点的开始位置
  13. xulie[now] = x;//把这个序号的节点加入到序列中
  14. int len = a[x].size();//这是x节点的出度
  15. for(int i = 0;i <= len-1;i++)//vector是从0开始计数的
  16. {
  17. int y = a[x][i];//x的一个出度。
  18. if (y!=pre)//如果没有往回走
  19. {
  20. dis[y] = dis[x]+v[y];//更新y节点它到0点的价值和
  21. dfs(y,x);//继续dfs
  22. }
  23. }
  24. e[x] = now;//这是节点的结束位置。b[x]..e[x]里面存的都是x的子树节点。
  25. }
  26. long long max(long long a,long long b)
  27. {
  28. return a > b?a:b;
  29. }
  30. void push_up(int rt)
  31. {
  32. maxsum[rt] = max(maxsum[rt<<1],maxsum[rt<<1|1]);//只要左右区间的最值取max就可以了。
  33. }
  34. void build(int l,int r,int rt)
  35. {
  36. lazy_tag[rt] = maxsum[rt] = 0;//初始化懒惰标记和区间最值。
  37. if (l == r)//如果左右指针相同
  38. {
  39. maxsum[rt] = dis[xulie[l]];//这个区间的最大值就是本身
  40. return;//注意不要写成maxsum[rt] = dis[l],l是dfs序,xulie[l]才是这个dfs序所代表的点
  41. }
  42. int m = (l+r)>>1;//取得中点
  43. build(l,m,rt<<1);//左递归建树
  44. build(m+1,r,rt<<1|1);//右递归建树
  45. push_up(rt);//根据儿子更新当前区间的最值。
  46. }
  47. void push_down(int rt)
  48. {
  49. if (lazy_tag[rt]!=0) //如果懒惰标记标记的值不为0
  50. {
  51. maxsum[rt<<1]+=lazy_tag[rt];//更新儿子节点们的区间最值(记住是同等更新就好)
  52. maxsum[rt<<1|1] += lazy_tag[rt];
  53. lazy_tag[rt<<1]+=lazy_tag[rt];//更新儿子节点们的懒惰标记。
  54. lazy_tag[rt<<1|1]+=lazy_tag[rt];
  55. lazy_tag[rt]=0;//把当前节点的懒惰标记置为0;
  56. }
  57. }
  58. void updata(int l,int r,int num,int begin,int end,int rt) //所要修改的区间为l,r,当前节点rt的区间
  59. {//为begin,end,然后要递增的值为num
  60. if (l <= begin && end <= r) //如果当前节点所在的区间被所要修改的区间覆盖
  61. {
  62. maxsum[rt]+=num;//递增这个区间的最大值(因为是同等递增,所以直接把最大值+递增值就可以);
  63. lazy_tag[rt] +=num;//标一个懒惰标记。
  64. return;
  65. }
  66. push_down(rt);//处理懒惰标记。
  67. int m = (begin+end)>>1;//取中点
  68. if (l <= m)//往左递增值
  69. updata(l,r,num,begin,m,rt<<1);
  70. if (m < r)//往右递增值。
  71. updata(l,r,num,m+1,end,rt<<1|1);
  72. push_up(rt);//根据儿子节点更新当前节点。
  73. }
  74. long long query(int l,int r,int begin,int end,int rt)//要找的区间为l,r,当前节点rt所代表的区间为begin,end;
  75. {
  76. if (l <= begin && end <= r)//如果当前节点所在的区间完全在要找的区间内
  77. return maxsum[rt];//就直接返回这个区间的最大值
  78. long long temp_ans= -10000000000;//这是用于取左右区间最大值的较大值。
  79. int m = (begin+end)>>1;
  80. push_down(rt);//先处理懒惰标记!!!!!!!!!!!!
  81. if (l <= m)//如果左区间和所找的区间有交集,就看看左区间是否更大
  82. temp_ans = max(temp_ans,query(l,r,begin,m,rt<<1));
  83. if (m < r)//右区间同理
  84. temp_ans = max(temp_ans,query(l,r,m+1,end,rt<<1|1));
  85. return temp_ans;//返回左右区间的较大值即可。
  86. }
  87. int main()
  88. {
  89. //freopen("rush.txt","r",stdin);
  90. int t;
  91. scanf("%d",&t);//输入数据的组数
  92. for (int ii = 1;ii <= t;ii++)//不要写成while (t--)。。。这样写你要怎么输出呢。。。
  93. {
  94. now = 0;//dfs序号从0再重新开始
  95. for (int i = 0;i <= 100000;i++)//初始化某个点的出度信息。
  96. a[i].clear();
  97. printf("Case #%d:\n",ii);//输出这是第几组数据
  98. scanf("%d%d",&n,&m);//输入点和边的信息。
  99. for (int i = 1;i <= n-1;i++)//输入n-1条边(就是树了!)
  100. {
  101. int x,y;
  102. scanf("%d%d",&x,&y);//输入起点和终点
  103. a[x].push_back(y);//建一条双向边。
  104. a[y].push_back(x);
  105. }
  106. for (int i = 0;i <= n-1;i++)//输入点的初始价值。
  107. scanf("%lld",&v[i]);
  108. dis[0] = v[0];//从0到0就是0点的价值。
  109. dfs(0,-1);//进行dfs,获取0到所有点的价值和。
  110. build(1,n,1);//建树。
  111. for (int i = 1;i <= m;i++)//输入m个操作。
  112. {
  113. int op,x,y;
  114. scanf("%d",&op);//读取操作
  115. if (op == 0)//如果要改变某个值
  116. {
  117. scanf("%d%d",&x,&y);
  118. updata(b[x],e[x],y-v[x],1,n,1);//把替换操作改为递增操作。要进行修改的区间就是
  119. v[x] = y;//x的子树所在的区间。
  120. //v[x]下次可能还会用到所以要修改一下。
  121. }
  122. else
  123. {
  124. scanf("%d",&x);//读入x,表示要经过x(然后从x和x的子树节点里面选一个节点到那里)
  125. cout << query(b[x],e[x],1,n,1) << endl;//在x的子树节点所在区间内找最大价值
  126. }
  127. }
  128. }
  129. return 0;
  130. }
  1. #pragma comment(linker, "/STACK:1024000000,1024000000")
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<vector>
  6. using namespace std;
  7. typedef long long ll;
  8. const int maxn=1e5+7;
  9. int in[maxn], out[maxn], xulie[maxn];
  10. ll dis[maxn], v[maxn];
  11. vector<int> g[maxn];
  12. struct node{
  13. int l, r;
  14. ll maxx, lazy;
  15. }t[maxn<<2];
  16. int n, m, now;
  17. void init()
  18. {
  19. now=0;
  20. for(int i=0; i<=n; i++)
  21. {
  22. g[i].clear();
  23. }
  24. }
  25. void dfs(int rt, int fa)
  26. {
  27. in[rt]=++now;
  28. xulie[now]=rt;
  29. int len=g[rt].size();
  30. for(int i=0; i<len; i++)
  31. {
  32. int y=g[rt][i];
  33. if(y==fa) continue;
  34. dis[y]=dis[rt]+v[y];
  35. dfs(y, rt);
  36. }
  37. out[rt]=now;
  38. }
  39. void pushup(int rt)
  40. {
  41. t[rt].maxx=max(t[rt<<1].maxx, t[rt<<1|1].maxx);
  42. }
  43. void build(int rt, int l, int r)
  44. {
  45. t[rt].l=l;
  46. t[rt].r=r;
  47. t[rt].lazy=0;
  48. if(l==r)
  49. {
  50. t[rt].maxx=dis[xulie[l]];
  51. return ;
  52. }
  53. int mid=(l+r)>>1;
  54. build(rt<<1, l, mid);
  55. build(rt<<1|1, mid+1, r);
  56. pushup(rt);
  57. }
  58. void down(int rt)
  59. {
  60. if(t[rt].lazy!=0)
  61. {
  62. t[rt<<1].maxx+=t[rt].lazy;
  63. t[rt<<1].lazy+=t[rt].lazy;
  64. t[rt<<1|1].maxx+=t[rt].lazy;
  65. t[rt<<1|1].lazy+=t[rt].lazy;
  66. t[rt].lazy=0;
  67. }
  68. }
  69. void update(int rt, int l, int r, int y)
  70. {
  71. if(l<=t[rt].l && t[rt].r <=r)
  72. {
  73. t[rt].maxx+=y;
  74. t[rt].lazy+=y;
  75. return ;
  76. }
  77. down(rt);
  78. int mid=(t[rt].l+t[rt].r)>>1;
  79. if(l<=mid) update(rt<<1, l, r, y);
  80. if(r>mid) update(rt<<1|1, l, r, y);
  81. pushup(rt);
  82. }
  83. ll query(int rt, int l, int r)
  84. {
  85. if(l<= t[rt].l && t[rt].r<=r)
  86. {
  87. return t[rt].maxx;
  88. }
  89. ll ans=-1e18;
  90. int mid=(t[rt].l+t[rt].r)>>1;
  91. down(rt);
  92. if(l<=mid) ans=max(ans, query(rt<<1, l, r));
  93. if(r>mid) ans=max(ans, query(rt<<1|1, l, r));
  94. return ans;
  95. }
  96. int main()
  97. {
  98. int t;
  99. scanf("%d", &t);
  100. for(int ca=1; ca<=t; ca++)
  101. {
  102. scanf("%d%d", &n, &m);
  103. init();
  104. printf("Case #%d:\n", ca);
  105. for(int i=1; i<n; i++)
  106. {
  107. int x, y;
  108. scanf("%d%d", &x, &y);
  109. g[x].push_back(y);
  110. g[y].push_back(x);
  111. }
  112. for(int i=0; i<=n-1; i++)
  113. {
  114. scanf("%lld", &v[i]);
  115. }
  116. dis[0]=v[0];
  117. dfs(0, -1);
  118. build(1, 1, n);
  119. for(int i=1; i<=m; i++)
  120. {
  121. int op, x, y;
  122. scanf("%d", &op);
  123. if(op==0)
  124. {
  125. scanf("%d%d", &x, &y);
  126. update(1,in[x], out[x], y-v[x]);
  127. v[x]=y;
  128. }
  129. else
  130. {
  131. scanf("%d", &x);
  132. printf("%lld\n", query(1, in[x], out[x]));
  133. }
  134. }
  135. }
  136. return 0;
  137. }

Snacks HDU 5692 dfs序列+线段树的更多相关文章

  1. hdu 5692(dfs序+线段树,好题)

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  2. HDU 5692 (DFS序+线段树)

    DFS获得从0到每一个顶点的距离,同时获得L和R数组.两数组为遍历时从i进入再从i出来的序列. #pragma comment(linker, "/STACK:1024000000,1024 ...

  3. hdu 3974 dfs时间戳+线段树

    题意: 一个公司里面每个员工都有一个顶头上司,一旦给某个员工分配任务后,这个员工以及该员工的所有下属都在做该任务. 有若干操作,分配给员工任务以及查询该员工正在执行的任务. 题解: 典型的更新字树的操 ...

  4. HDU 5877 [dfs序][线段树][序]

    /* 题意: n个点的树,每个点给定一个权值,给定一个k,求任意一点的子树中,权值小于k/该点权值的点共有多少个. 思路: 1.很明显的子树的操作,应用dfs序. 2.比赛的时候傻逼了,一直在调划分树 ...

  5. Assign the task HDU - 3974 (dfs序 + 线段树)

    有一家公司有N个员工(从1到N),公司里每个员工都有一个直接的老板(除了整个公司的领导).如果你是某人的直接老板,那个人就是你的下属,他的所有下属也都是你的下属.如果你是没有人的老板,那么你就没有下属 ...

  6. HDU 5692 Snacks bfs版本dfs序 线段树

    Snacks 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5692 Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连 ...

  7. HDU.5692 Snacks ( DFS序 线段树维护最大值 )

    HDU.5692 Snacks ( DFS序 线段树维护最大值 ) 题意分析 给出一颗树,节点标号为0-n,每个节点有一定权值,并且规定0号为根节点.有两种操作:操作一为询问,给出一个节点x,求从0号 ...

  8. dfs序 线段树 dfs序列 主席树

    并查集 #include<stdio.h> ]; void sset(int x) { ;i<=x;i++) stt[i]=i; } int ffind(int x) { if(x= ...

  9. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

随机推荐

  1. 前端之JQuery:JQuery文档操作

    jquery之文档操作 一.相关知识点总结1.CSS .css() - .css("color") -> 获取color css值 - .css("color&qu ...

  2. 前端之JavaScript:JS之DOM对象三

    js之DOM对象三   一.JS中for循环遍历测试 for循环遍历有两种 第一种:是有条件的那种,例如    for(var i = 0;i<ele.length;i++){} 第二种:for ...

  3. CF547E Mike and Friends

    子串看起来就很SuffixStructures 于是上SAM 本来想着直接LCT 后来发现没法串定位(暴力匹配复杂度不对) 然后就离线吧,先建出来然后链加子树和,树剖就odk. 其实更直接的套路是线段 ...

  4. Python---面向对象---案例

    a = 5print(5/10)# 地板除(功能类似于数学模块当中floor()向下取整操作)print(5//10)print(a%10)b = 25print(b/10)print(b//10)p ...

  5. Task5.PyTorch实现L1,L2正则化以及Dropout

    1.了解知道Dropout原理 深度学习网路中,参数多,可能出现过拟合及费时问题.为了解决这一问题,通过实验,在2012年,Hinton在其论文<Improving neural network ...

  6. python-获取类名和方法名,动态创建类和方法及属性

    获取类名和方法名1.在函数外部获取函数名称,用.__name__获取2.在函数内部获取当前函数名称,用sys._getframe().f_code.co_name方法获取3.使用inspect模块动态 ...

  7. linux运维、架构之路-redis集群

    一.介绍            redis cluster 3.0之后的功能,至少需要3(Master)+3(Slave)才能建立集群,是无中心的分布式存储架构,可以在多个节点之间进行数据共享,解决了 ...

  8. jq 获取各个元素的宽度高度的方法

    JS获取各种宽度.高度的简单介绍: scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 scrollTop:设置或获 ...

  9. Spring——IOC与Bean容器

    [IOC] (1)IOC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护.也就是说由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中 (2)DI: ...

  10. hdu_1231(最大连续子序列)

    http://acm.hdu.edu.cn/showproblem.php?pid=1231 最长公共子序列: 方法1:暴力枚举所有区间的连续和,维护最大和 复杂度O(n^3)-->因为求区间和 ...