【hdu5692】Snacks
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1629 Accepted Submission(s): 396
由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。
为小度熊规划一个路线,使得路线上的价值总和最大。
对于每组数据,包含两个整数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++,并在代码的第一行加上:
`#pragma comment(linker, "/STACK:1024000000,1024000000") `
对于每次询问,输出从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。
1 6 5 0 1 1 2 0 3 3 4 5 3 7 -5 100 20 -5 -7 1 1 1 3 0 2 -1 1 1 1 5
Case #1: 102 27 2 20
【题解】
被自己坑得好惨。
1是忘记在询问里面处理懒惰标记。
2是多组数据的输出。我写的是while(t--)这样的形式。然后就顺势输出Case #t+1:了。。。刚好可以过样例。。
但是如果T=10,则输出的第一个是Case #10:然后是Case #9:啊!!!!!
然后讲一下做题的思路。
需要用到dfs序
这个东西主要是用来确定一个树的某个节点的子树里面的节点有哪些。
比如这样的一棵树
从根节点进行dfs,其dfs序为
1 2 4 4 5 5 2 3 6 6 7 7 3 1
可以看到两个相同的数字之间就是以这个数字为根的子树里面的所有节点。
我们在记录的时候不需要记录相同的数字直接
记录1 2 4 5 3 6 7即可
然后我们再记录某个元素它会在哪里再出现一次
比如b[1] = 1;
e[1] = 7;
b[2] = 2;e[2] = 4;
。。。
这样我们就记录下了以x元素为根节点的子树里面的所有元素所在的区间。
为什么要知道这个???
想想看。n-1条边,(而且还能联通整张图),那不就是一棵树吗???
然后要让它必须经过x,那不就是说一定要到达x吗??
然后到达了x要怎么办??
继续往下走??
走到哪里??
只能是x的子树啦(所有节点最多只能走一次)
一开始从根节点0到树中某个点的总价值是固定的(路径唯一)。
那我们就要从x的子树里面寻找一个节点。这个节点满足从0到此节点的路径上获得的价值最大。
我们一开始把0到某个点x的价值和算出来(dfs一遍)然后存在dis[0..n-1]中
那么dis[0],dis[1],dis[2],dis[3],dis[4],dis[5]...dis[n-1]就是区间上的一个个点。
然后如果要求一定要到3,那么就看一下b[3]和e[3]是多少;
b[3]..e[3]就是一段区间(肯定是连续的,且这段区间里面全是3的子树节点)
那么我们就要求max{dis[b[3]..e[3]]};
这不就是维护区间最值吗?
然后会出现让某个节点变为y的情况。
其实如果单纯就按照它的做法替换是不好做的
我们可以转换成递增来做
把v[x]替换成y;实际上就是给v[x]加上y-v[x];
然后对x的更改只会改变x的子树里面的dis值。
而实际上就是x的所有子树节点(包括x本身)的dis值都加上y-v[x]。
这就是一个区间递增的问题了。
具体的看程序注释
不要忘了加防爆栈的那行代码。
【代码】
- #pragma comment(linker, "/STACK:1024000000,1024000000")
- #include <cstdio>
- #include <cstring>
- #include <vector>
- #include <iostream>
- using namespace std;
- vector <int> a[100001];
- int n,m,now = 0,b[100001],xulie[100005],e[100005];
- long long v[100005],dis[100005] ={0},maxsum[100005*4],lazy_tag[100005*4] = {0};
- void dfs(int x,int pre)//深搜找dfs序
- {
- b[x] = ++now;//这是这个节点的开始位置
- xulie[now] = x;//把这个序号的节点加入到序列中
- int len = a[x].size();//这是x节点的出度
- for(int i = 0;i <= len-1;i++)//vector是从0开始计数的
- {
- int y = a[x][i];//x的一个出度。
- if (y!=pre)//如果没有往回走
- {
- dis[y] = dis[x]+v[y];//更新y节点它到0点的价值和
- dfs(y,x);//继续dfs
- }
- }
- e[x] = now;//这是节点的结束位置。b[x]..e[x]里面存的都是x的子树节点。
- }
- long long max(long long a,long long b)
- {
- return a > b?a:b;
- }
- void push_up(int rt)
- {
- maxsum[rt] = max(maxsum[rt<<1],maxsum[rt<<1|1]);//只要左右区间的最值取max就可以了。
- }
- void build(int l,int r,int rt)
- {
- lazy_tag[rt] = maxsum[rt] = 0;//初始化懒惰标记和区间最值。
- if (l == r)//如果左右指针相同
- {
- maxsum[rt] = dis[xulie[l]];//这个区间的最大值就是本身
- return;//注意不要写成maxsum[rt] = dis[l],l是dfs序,xulie[l]才是这个dfs序所代表的点
- }
- int m = (l+r)>>1;//取得中点
- build(l,m,rt<<1);//左递归建树
- build(m+1,r,rt<<1|1);//右递归建树
- push_up(rt);//根据儿子更新当前区间的最值。
- }
- void push_down(int rt)
- {
- if (lazy_tag[rt]!=0) //如果懒惰标记标记的值不为0
- {
- maxsum[rt<<1]+=lazy_tag[rt];//更新儿子节点们的区间最值(记住是同等更新就好)
- maxsum[rt<<1|1] += lazy_tag[rt];
- lazy_tag[rt<<1]+=lazy_tag[rt];//更新儿子节点们的懒惰标记。
- lazy_tag[rt<<1|1]+=lazy_tag[rt];
- lazy_tag[rt]=0;//把当前节点的懒惰标记置为0;
- }
- }
- void updata(int l,int r,int num,int begin,int end,int rt) //所要修改的区间为l,r,当前节点rt的区间
- {//为begin,end,然后要递增的值为num
- if (l <= begin && end <= r) //如果当前节点所在的区间被所要修改的区间覆盖
- {
- maxsum[rt]+=num;//递增这个区间的最大值(因为是同等递增,所以直接把最大值+递增值就可以);
- lazy_tag[rt] +=num;//标一个懒惰标记。
- return;
- }
- push_down(rt);//处理懒惰标记。
- int m = (begin+end)>>1;//取中点
- if (l <= m)//往左递增值
- updata(l,r,num,begin,m,rt<<1);
- if (m < r)//往右递增值。
- updata(l,r,num,m+1,end,rt<<1|1);
- push_up(rt);//根据儿子节点更新当前节点。
- }
- long long query(int l,int r,int begin,int end,int rt)//要找的区间为l,r,当前节点rt所代表的区间为begin,end;
- {
- if (l <= begin && end <= r)//如果当前节点所在的区间完全在要找的区间内
- return maxsum[rt];//就直接返回这个区间的最大值
- long long temp_ans= -10000000000;//这是用于取左右区间最大值的较大值。
- int m = (begin+end)>>1;
- push_down(rt);//先处理懒惰标记!!!!!!!!!!!!
- if (l <= m)//如果左区间和所找的区间有交集,就看看左区间是否更大
- temp_ans = max(temp_ans,query(l,r,begin,m,rt<<1));
- if (m < r)//右区间同理
- temp_ans = max(temp_ans,query(l,r,m+1,end,rt<<1|1));
- return temp_ans;//返回左右区间的较大值即可。
- }
- int main()
- {
- //freopen("rush.txt","r",stdin);
- int t;
- scanf("%d",&t);//输入数据的组数
- for (int ii = 1;ii <= t;ii++)//不要写成while (t--)。。。这样写你要怎么输出呢。。。
- {
- now = 0;//dfs序号从0再重新开始
- for (int i = 0;i <= 100000;i++)//初始化某个点的出度信息。
- a[i].clear();
- printf("Case #%d:\n",ii);//输出这是第几组数据
- scanf("%d%d",&n,&m);//输入点和边的信息。
- for (int i = 1;i <= n-1;i++)//输入n-1条边(就是树了!)
- {
- int x,y;
- scanf("%d%d",&x,&y);//输入起点和终点
- a[x].push_back(y);//建一条双向边。
- a[y].push_back(x);
- }
- for (int i = 0;i <= n-1;i++)//输入点的初始价值。
- scanf("%lld",&v[i]);
- dis[0] = v[0];//从0到0就是0点的价值。
- dfs(0,-1);//进行dfs,获取0到所有点的价值和。
- build(1,n,1);//建树。
- for (int i = 1;i <= m;i++)//输入m个操作。
- {
- int op,x,y;
- scanf("%d",&op);//读取操作
- if (op == 0)//如果要改变某个值
- {
- scanf("%d%d",&x,&y);
- updata(b[x],e[x],y-v[x],1,n,1);//把替换操作改为递增操作。要进行修改的区间就是
- v[x] = y;//x的子树所在的区间。
- //v[x]下次可能还会用到所以要修改一下。
- }
- else
- {
- scanf("%d",&x);//读入x,表示要经过x(然后从x和x的子树节点里面选一个节点到那里)
- cout << query(b[x],e[x],1,n,1) << endl;//在x的子树节点所在区间内找最大价值
- }
- }
- }
- return 0;
- }
【hdu5692】Snacks的更多相关文章
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
- Python高手之路【一】初识python
Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...
- 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】
说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
随机推荐
- vmware workstation15.1.0下载地址及密钥(亲测可用)
官网下载链接: https://download3.vmware.com/software/wkst/file/VMware-workstation-full-15.1.0-13591040.exe ...
- jquery实现转盘抽奖
jquery实现转盘抽奖 一.总结 一句话总结:这里环形转盘,环形的东西可以化成线性的,然后访问到哪个,给他加上背景为红的样式,用定时器开控制转盘的速度,函数执行的时间间隔越小,就运动的越快. 1.如 ...
- Visual Studio Team Services持续集成到Github仓库
Devops如何用VSTS持续集成到Github仓库! 工欲善其事,必先利其器.在开始正式的教程之前我们先来聊聊准备工作. 管理工具会VSTS. 代码管理会用GITHUB. 服务器会用Azure. ...
- Python 极简教程(八)字符串 str
由于字符串过于重要,请认真看完并保证所有代码都至少敲过一遍. 对于字符串,前面在数据类型中已经提到过.但是由于字符串类型太过于常用,Python 中提供了非常多的关于字符串的操作.而我们在实际编码过程 ...
- 关于在IISserver上执行asp.net Web程序出现以下 “Could not load file or assembly。。。”问题的
Could not load file or assembly 'System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, Public ...
- Altium Designer的pcb界面如何让线变成点
但是16版本,需要tools --- Grid Manager --双击 双击后: 转自:http://blog.csdn.net/ldcung/article/details/77411434
- Surging 分布式微服务框架使用入门
原文:Surging 分布式微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与S ...
- SorceTree 与 Bitbucket连接
选择bitbucket,由于bitbucket免费的帐号最多能够8个人一起协同开发.我们项目组人数少于8个,私有仓库也不限制. 经过半个多月的应用,大家感觉也还不错,对个人而言.在家也能訪问代码,对公 ...
- (转)Nginx在RedHat中系统服务配置脚本
转自:http://binyan17.iteye.com/blog/1688308 以下代码是在前人的基础上,结合自己服务器实际情况修改的,本人服务器环境是:CentOS 6.31.创建启动脚本, ...
- JVM学习:方法重载的优先级
重载:方法名一致,参数长度或者类型不一致. 先放总结,下面为例子 参数具有继承.实现关系,优先考虑子类: 在不考虑对基本类型自动装拆箱(auto-boxing,auto-unboxing),以及可变长 ...