问题 K(2415): 幸福的道路
时间限制: 3 Sec 内存限制: 128 MB
题目描述
小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.
他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.
他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条).
他们不愿再经历之前的大起大落,所以决定连续几天的幸福值波动不能超过M(即一段连续的区间并且区间的最大值最小值之差不超过M).他们想知道要是这样的话他们最多能连续锻炼多少天(hint:不一定从第一天一直开始连续锻炼)?
输入
第一行包含两个整数N,M(M≤109).
第二至第N行,每行两个数字Fi ,Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.
输出
最长的连续锻炼天数
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
3 2 1 1 1 3
样例输出
3
提示
50%的数据N≤1000
80%的数据N≤100000
100%的数据N≤1000000
分析:
首先,求出树中每个点到树中最远点的距离,存于 f 数组中
定义树的直径为树中最长链,则 f[i] = max(dis(i,直径的一端点),dis(i,直径的另一端点))
证明: 显然,距离u点最远的点,即从u开始dfs找到的最远点
设点v是u的最远点
(1) 若u在直径上,则v必为直径一端点,若不是,设直径端点为w,则dis[u][v]>dis[u][w],直径可以更长,矛盾
(2) 若u不在直径上,则u到v必与直径相交,反证如下图:
求出f[i]后,就是在f数组中求振幅(max-min)小于等于m的最大长度
用L,R在1~n移动,同时用单调栈维护最大和最小值,不满足则L++,同时弹出栈中在L之前的值
#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 1000005
using namespace std;
int n,m,ans;
int fir[maxn],nxt[2*maxn],to[2*maxn],w[2*maxn],tot;
long long f[maxn];
int S1[maxn],S2[maxn],h1,h2,t1=-1,t2=-1;
inline void get(int &a)
{
char c;a=0;
while(!isdigit(c=getchar()));
while(isdigit(c)) a=a*10+c-'0',c=getchar();
}
inline void line(int x,int y,int z)
{
nxt[++tot]=fir[x];
fir[x]=tot;
to[tot]=y;
w[tot]=z;
}
inline void dfs(int u,int past,long long s,int &id)
{
if(s>f[id]) id=u;
if(s>f[u]) f[u]=s;
for(int i=fir[u];i;i=nxt[i])
if(to[i]!=past) dfs(to[i],u,s+w[i],id);
}
int main()
{
int x,y,L;
get(n),get(m);
for(int i=2;i<=n;i++)
get(x),get(y),line(i,x,y),line(x,i,y);
x=y=0,dfs(1,0,0,x);
dfs(x,0,0,y);
dfs(y,0,0,x);
L=1;
for(int i=1;i<=n;i++)
{
while(t1>=h1&&f[S1[t1]]<=f[i]) t1--;
S1[++t1]=i;
while(t2>=h2&&f[S2[t2]]>=f[i]) t2--;
S2[++t2]=i;
while(f[S1[h1]]-f[S2[h2]]>m)
{
if(L==S1[h1]) h1++;
if(L==S2[h2]) h2++;
L++;
}
ans=max(ans,i-L+1);
}
printf("%d",ans);
}