[BZOJ 2500]幸福的道路 树形dp+单调队列+二分答案
考试的时候打了个树链剖分,而且还审错题了,以为是每天找所有点的最长路,原来是每天起点的树上最长路径再搞事情。。
先用dfs处理出来每个节点以他为根的子树的最长链和次长链。(后面会用到)
然后用类似dp的方法把每个节点的最长路径求出来。
下面是具体解释,请思考
以一个节点为例(w为它与父亲节点道路的权值)
一、如果它父亲节点的最长路径不过它
那么它最长路径等于它父亲最长路径+w(自己画图即可理解,往上走的)
它的次长路径等于它的最长链(只能往下走)
二、如果过它
那么它的最长路径有两种可能
①它的最长链
②它父亲的次长路径+w
如果①优,那么它最长路径为①,次长路径为max(它的次长链,②)
如果②优,那么它最长路径为②,次长路径为①
很好理解吧。。。
然后让求最大值与最小值差在m之内的最长子串。
据他们说有O(n)的做法,不过我打了O(nlogn)的打法,跑进了1s,反正O(能过)就行。
我的nlogn是二分答案+单调队列。二分答案去验证,挨个移动,看是否满足条件。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
int n,m;
#define N 1001000
struct haha
{
int to,next,w;
};
int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
return x;
}
haha edge[N*4];
int head[N],cnt=1;
void add(int u,int v,int w)
{
edge[cnt].w=w;
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
struct qian
{
int fir,firch; int sec,secch;
int roadfir,roadsec;int roadfirch,roadsecch;
}cun[N];
int fa[N];
void dfs(int now)
{
for(int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
int w=edge[i].w;
dfs(to);
if(cun[now].sec<cun[to].fir+w)
{
cun[now].sec=cun[to].fir+w;
cun[now].secch=to;
if(cun[now].sec>cun[now].fir)
{
swap(cun[now].sec,cun[now].fir);
swap(cun[now].secch,cun[now].firch);
}
}
}
}
void dp(int now,int w)
{
if(now==1)
{
cun[now].roadfir=cun[now].fir;
cun[now].roadsec=cun[now].sec;
cun[now].roadfirch=cun[now].firch;
cun[now].roadsecch=cun[now].secch;
}
else
{
if(cun[fa[now]].roadfirch!=now)
{
cun[now].roadfir=cun[fa[now]].roadfir+w;
cun[now].roadfirch=fa[now];
cun[now].roadsec=cun[now].fir;
}
else
{
if(cun[now].fir>cun[fa[now]].roadsec+w)
{
cun[now].roadfir=cun[now].fir;
cun[now].roadfirch=cun[now].firch;
cun[now].roadsec=max(cun[now].sec,cun[fa[now]].roadsec+w);
}
else
{
cun[now].roadfir=cun[fa[now]].roadsec+w;
cun[now].roadfirch=fa[now];
cun[now].roadsec=cun[now].fir;
}
}
}
for(int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
int ww=edge[i].w;
dp(to,ww);
}
}
int f[N];
int qmax[N],hed,tail;
int qmin[N],beg,ed;
bool find(int val){
hed=tail=0;
beg=ed=0;
for(int i=1;i<=n;i++){
while(hed<tail&&i-qmax[hed]>=val) hed++;
while(beg<ed&&i-qmin[beg]>=val) beg++;
while(hed<tail&&f[qmax[tail-1]]<f[i]) tail--;qmax[tail++]=i;
while(beg<ed&&f[qmin[ed-1]]>f[i]) ed--;qmin[ed++]=i;
if(i>=val&&f[qmax[hed]]-f[qmin[beg]]<=m) return true;
}
return false;
}
int main()
{
//freopen("race.in","r",stdin);
//freopen("race.out","w",stdout);
n=read();m=read();
pos(i,2,n)
{
int x,y;
x=read();y=read();
add(x,i,y);
fa[i]=x;
}
dfs(1);
dp(1,0);
for(int i=1;i<=n;i++)
cout<<cun[i].roadfir<<" "<<cun[i].roadsec<<endl;
while(1);
for(int i=1;i<=n;i++)
f[i]=cun[i].roadfir;
int l=1,r=n+1;
while(l<r-1){
int mid=l+r>>1;
if(find(mid))l=mid;
else r=mid;
}
int l=1,r=n+1;
while(l<r-1)
{
int mid=(l+r)>>1;
if(find(mid))
l=mid;
else
r=mid;
}
cout<<l;
//while(1);
return 0;
}
[BZOJ 2500]幸福的道路 树形dp+单调队列+二分答案的更多相关文章
- (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列
Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. ...
- bzoj2500幸福的道路 树形dp+单调队列
2500: 幸福的道路 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 434 Solved: 170[Submit][Status][Discuss ...
- 【bzoj2500】幸福的道路 树形dp+单调队列
Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. ...
- 【bzoj2500】幸福的道路 树形dp+倍增RMQ+二分
原文地址:http://www.cnblogs.com/GXZlegend/p/6825389.html 题目描述 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一 ...
- [BZOJ 2500] 幸福的道路
照例先贴题面(汪汪汪) 2500: 幸福的道路 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 368 Solved: 145[Submit][Sta ...
- bzoj2500: 幸福的道路(树形dp+单调队列)
好题.. 先找出每个节点的树上最长路 由树形DP完成 节点x,设其最长路的子节点为y 对于y的最长路,有向上和向下两种情况: down:y向子节点的最长路g[y][0] up:x的次长路的g[x][1 ...
- ●BZOJ 2500 幸福的道路
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2500 题解: DFS,单调队列 首先有一个结论,距离树上某一个点最远的点一定是树的直径的一个 ...
- 【BZOJ2500】幸福的道路 树形DP+RMQ+双指针法
[BZOJ2500]幸福的道路 Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的 ...
- Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列
原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...
随机推荐
- 【Android Developers Training】 103. 查询当前地点
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- WCF学习——构建第二个WCF应用程序(五)
一.创建数据服务 1.在“解决方案资源管理器”中,使用鼠标左键选中“WcfService”项目,然后在菜单栏上,依次选择“项目”.“添加新项”. 2.在“添加新项”对话框中,选择“Web”节点,然后选 ...
- webpack教程(二)——webpack.config.js文件
首先我们需要安装一个webpack插件html-webpack-plugin,该插件的作用是帮助我们生成创建html入口文件.执行如下命令 npm install html-webpack-plugi ...
- Linux 内核综述
一.什么是Linux内核: 内核->操作系统中最重要的部分,内核将在系统引导时被装载进RAM,其中包含了很多关键的例程,以操作系统.内核是OS最为关键的部分,人们常将OS(操作系统)与内核等同. ...
- tp5框架的获取器
tp5的获取器功能很强大,一下子就喜欢上了,你可以在模块里任意定义表里不存在的字段,在前台调用很方便.话不多说直接上demo: 1.命名规则 get + 属性名的驼峰命名+ Attr 直接就能在m ...
- 将git版本号编译进程序
问题的提出 不管是什么版本管理工具,每一条提交记录都会有一个对应的版本号,一般是一个整数,git是一个hash字符串.不管怎样,这个版本号是唯一的,有时候我们在程序运行的时候会在日志里面输出程序的版本 ...
- js中的数组排序
js数组冒泡排序,快速排序的原理以及实现 冒泡排序: 随便从数组中拿一位数和后一位比较,如果是想从小到大排序,那么就把小的那一位放到前面,大的放在后面,简单来说就是交换它们的位置,如此反复的交换位 ...
- 基于python的二元霍夫曼编码译码详细设计
一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图 ...
- 【翻译】React vs Angular: JavaScript的双向性
翻译原文链接:https://blog.prototypr.io/react-vs-angular-two-sides-of-javascript-b850de22b413 我的翻译小站:http:/ ...
- JavaScript Base64加解密
Base64加密算法是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045-RFC2049,上面有MIME的详细规范.Base64编码可用于在HTTP环境下传递较长的标识信 ...