Description
小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.
他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.
他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线.
他们不愿再经历之前的大起大落,所以决定连续几天的幸福值波动不能超过M.他们想知道要是这样的话他们最多能连续锻炼多少天(hint:不一定从第一天一直开始连续锻炼)?
现在,他们把这个艰巨的任务交给你了!
Input
第一行包含两个整数N, M(M<=10^9).
第二至第N行,每行两个数字Fi , Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.
Output
最长的连续锻炼天数
数据范围:
50%的数据N<=1000
80%的数据N<=100000
100%的数据N<=1000000
Analysis
先考虑树形dp,设f[i]表示节点i向下能走的最长路,g[i]表示节点i向上再向下能走的最长路
由于不能走重复的路,我们发现这样显然是不行的(向上再向下会走重复的某一段)。于是改一下f[i][0]、f[i][1]分别表示节点i向下走的最长路和次长路,g[i][0]、g[i][1]同理,用两个dfs转移状态
为了找到连续的最长一段极值差不超过m的序列,解决方法是分别开单调递减和单调递增的两个队列就可以了
Code
/*
ID:wjp13241
PROG:myp
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fore(i,x,e) for(int i=ls[x];i;i=e[i].next)
#define fil(x,t) memset(x,t,sizeof(x))
#define max(x,y) x>y?x:y
#define INF 0x3f3f3f3f
#define N 1000005
#define E N*2+1
using namespace std;
struct edge{int y,w,next;}e[E];
int d[N][2],r[N][2],ls[N],q[N],t[N],maxE=0;
int add(int x,int y,int w){e[++maxE]=(edge){y,w,ls[x]};ls[x]=maxE;}
inline int read(){
int x=0,v=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')v=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*v;
}
inline int dfsD(int fa,int x)
{
fore(i,x,e)
if (e[i].y!=fa)
{
int y=e[i].y,w=e[i].w;
dfsD(x,y);
if (d[y][0]+w>d[x][0])
{
d[x][1]=d[x][0];
r[x][1]=r[x][0];
d[x][0]=d[y][0]+w;
r[x][0]=y;
}
else
if (d[y][0]+w>d[x][1])
{
d[x][1]=d[y][0]+w;
r[x][1]=y;
}
}
}
inline int dfsF(int fa,int x,int l)
{
int w=l+d[fa][0];
if (r[fa][0]==x)
w=l+d[fa][1];
if (w>d[x][0])
{
d[x][1]=d[x][0];
r[x][1]=r[x][0];
d[x][0]=w;
r[x][0]=fa;
}
else
if (w>d[x][1])
{
d[x][1]=w;
r[x][1]=fa;
}
fore(i,x,e)
if (e[i].y!=fa)
dfsF(x,e[i].y,e[i].w);
}
int main()
{
int n=read(),m=read();
fo(i,2,n)
{
int x=read(),w=read();
add(x,i,w);
add(i,x,w);
}
dfsD(0,1);
dfsF(0,1,0);
int qh=1,qt=0,th=1,tt=0,ans=0,id=0;
fo(i,1,n)
{
while (qh<=qt&&d[i][0]<=d[q[qt]][0])
qt--;
q[++qt]=i;
while (th<=tt&&d[i][0]>=d[t[tt]][0])
tt--;
t[++tt]=i;
while (d[t[th]][0]-d[q[qh]][0]>m)
if (q[qh]<t[th])
id=q[qh++];
else
id=t[th++];
ans=max(ans,i-id);
}
printf("%d\n",ans);
return 0;
}

350

被折叠的 条评论
为什么被折叠?



