bzoj2500幸福的道路 树形dp+单调队列

2500: 幸福的道路

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 434  Solved: 170
[Submit][Status][Discuss]

Description

小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.

他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.

他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条).

他们不愿再经历之前的大起大落,所以决定连续几天的幸福值波动不能超过M(即一段连续的区间并且区间的最大值最小值之差不超过M).他们想知道要是这样的话他们最多能连续锻炼多少天(hint:不一定从第一天一直开始连续锻炼)?

现在,他们把这个艰巨的任务交给你了!

Input

第一行包含两个整数N, M(M<=10^9).

第二至第N行,每行两个数字Fi , Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.

Output

最长的连续锻炼天数

Sample Input

3 2
1 1
1 3

Sample Output

3
数据范围:
50%的数据N<=1000
80%的数据N<=100 000
100%的数据N<=1000 000

这其实是两个题强行合在一起啊。。
首先是对于每个节点求它在树上的最长路,可以树形dp 2次,一次从儿子转移一次从父亲转移
求最长连续区间的话维护两个单调队列max min就好

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define N 1000005
 6 #define ll long long
 7 using namespace std;
 8 int n,m,tot,w[N],hd[N],ans=1;
 9 ll f[N],g[N],a[N];int mx[N],mn[N];
10 struct edge{int v,w,next;}e[N<<1];
11 char gc(){
12     static char s[1000000],*p1,*p2;
13     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
14     if(p1==p2)return EOF;
15     return *p1++;
16 }
17 int read(){
18     int x=0;char ch=gc();
19     while(ch>‘9‘||ch<‘0‘)ch=gc();
20     while(ch<=‘9‘&&ch>=‘0‘)x=x*10+ch-‘0‘,ch=gc();
21     return x;
22 }
23 void adde(int u,int v,int w){
24     e[++tot].v=v;
25     e[tot].next=hd[u];
26     e[tot].w=w;
27     hd[u]=tot;
28 }
29 void dfs1(int u,int fa){
30      for(int i=hd[u];i;i=e[i].next){
31          int v=e[i].v;
32          if(v==fa)continue;
33          dfs1(v,u);
34          f[u]=max(f[u],f[v]+e[i].w);
35      }
36 }
37 void dfs2(int u,int fa){
38     ll mx1=0,mx2=0;
39     for(int i=hd[u];i;i=e[i].next){
40         int v=e[i].v;if(v==fa)continue;
41         if(f[v]+e[i].w>mx1)mx2=mx1,mx1=f[v]+e[i].w;
42         else if(f[v]+e[i].w>mx2)mx2=f[v]+e[i].w;
43         g[v]=g[u]+e[i].w;
44     }
45     for(int i=hd[u];i;i=e[i].next){
46         int v=e[i].v;if(v==fa)continue;
47         if(f[v]+e[i].w==mx1)g[v]=max(g[v],mx2+e[i].w);
48         else if(mx1+e[i].w>g[v])g[v]=mx1+e[i].w;
49         dfs2(v,u);
50     }
51 }
52 void solve(){
53     for(register int i=1;i<=n;i++)a[i]=max(g[i],f[i]);
54     int l1=1,l2=1,r2=0,r1=0,t=1;
55     for(register int i=1;i<=n;i++){
56         while(l1<=r1&&a[i]>=a[mx[r1]])r1--;
57         while(l2<=r2&&a[i]<=a[mn[r2]])r2--;
58         mx[++r1]=i;mn[++r2]=i;
59         while(a[mx[l1]]-a[mn[l2]]>m){
60             if(mx[l1]<=mn[l2])t=mx[l1]+1,l1++;
61             else t=mn[l2]+1,l2++;
62         }
63         ans=max(ans,i-t+1);
64     }
65 }
66 int main(){
67      n=read();m=read();
68      for(register int i=2;i<=n;i++){
69          int v=read(),w=read();
70          adde(i,v,w);adde(v,i,w);
71      }dfs1(1,0);dfs2(1,0);
72      solve();printf("%d",ans);
73      return 0;
74 }

原文地址:https://www.cnblogs.com/wsy01/p/8111369.html

时间: 2024-09-29 15:27:27

bzoj2500幸福的道路 树形dp+单调队列的相关文章

BZOJ 2500 幸福的道路 树形DP+单调队列

题目大意:给定一棵树,令a[i]为从第i个节点出发的最长链,求a[i]中最长的区间,满足区间内最大值与最小值之差不超过m 读错题害死人,脑残害死人 求a[i]显然是树形DP 考虑从一个点出发的链可以从子节点走,也可以从父节点走 因此我们DP两次,第一次求出从子节点走的最长链,第二次求出从父节点走的最长链,两次取max就是答案 但是直接DP会有问题,因为从父节点走的最长链可能是从自己的子树出发的,这样就会走重 因此除记录从子节点出发的最长链外还要记录一个从另一个子节点出发的次长链,如果最长链长度相

bzoj2500: 幸福的道路(树形dp+单调队列)

好题.. 先找出每个节点的树上最长路 由树形DP完成 节点x,设其最长路的子节点为y 对于y的最长路,有向上和向下两种情况: down:y向子节点的最长路g[y][0] up:x的次长路的g[x][1]+dis[x][y] up:up[fa[x]]+dis[x][y] dfs1找向下,即向子节点的最长路 dfs2找向上的最长路 最后最长路f[i]=max(up[x],g[x][0]) 第二部分 找最长连续子序列,使得序列中abs(mx-mn)<=m 这次学习了用单调队列的做法 两个队列mx,mn

【BZOJ2500】幸福的道路 树形DP+RMQ+双指针法

[BZOJ2500]幸福的道路 Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. 他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条). 他

POJ - 3162 Walking Race 树形dp 单调队列

POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这样的区间最长的长度? 一开始楞是没看懂题意,最讨厌这种四级题,这是在刁难我英语小能手(能用翻译的就不自己动手).而且这题感觉单调队列那里的处理更难一点,不过还是来说一说怎么树形dp取得最远距离,先画个简简单单丑丑的图 我们直接从1作为根节点开始dfs的话,可以处理1的最远距离,并且可以得出到其它节点

hdu 4123 树形DP+单调队列

http://acm.hust.edu.cn/vjudge/problem/25790 这题基本同poj 3162 要注意mx,mx2,vx,vx2每次都要初始化 #include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm>

习题:烽火传递(DP+单调队列)

烽火传递[题目描述]烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定的代价.为了使情报准确的传递,在m个烽火台中至少要有一个发出信号.现输入n.m和每个烽火台发出的信号的代价,请计算总共最少需要花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确的传递!!![输入描述]第一行有两个数n,m(1<=n,m<=1000000)分别表示n个烽火台

poj3017 dp+单调队列

http://poj.org/problem?id=3017 Description Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of

12170 - Easy Climb(DP+单调队列)

该题需要用数据结构来优化DP ,具体方法就是之前第八章讲的(用数据结构优化算法,紫书P241),使用一个数组和两个指针维护一个单调队列, 可以在O(n)的时间内求出滑动窗口中的最小值 . 有了这个优化我们就可以快速的求出dp[i-1][j](x-d<=j<=x+d)的最小值. 然而刘汝佳就是不这么做,他只用了一个指针,连维护优先队列的数组都没开,就"隐式的"求出了最小值 . 具体做法是: 1.先维护窗口左边界,别让指针k超出了窗口,如果x[k] < x[j] - d那

UESTC 594 我要长高 dp单调队列优化入门

//其实是个伪单调队列...渣渣刚入门 //戳这里:594 //dp[ i ][ j(现身高) ] = min(    dp[ i ][ k(现身高) ]  + fabs( j(现身高) - k(现身高) ) * C + ( j(现身高) - h[i](原身高) )  *( j(现身高) - h[i](原身高) )     ); 观察到可以单调队列优化,O(N * H * H)  —>  O(N * H) j >= k 时, dp[ i ][ j ] = min (    dp[ i ][ k