题意:给一棵n个结点边带权的树,记结点i到其他结点最远距离为d[i]。
问d数组构成的这个序列中满足其中最大值与最小值的差不超过m的连续子序列最长是多长。
用树形dp来求树中的每个顶点到其他所有顶点距离的最大值。然后用单调队列求满足max-min<=m的连续子序列最长是多长。
//#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
struct node{
int x;
ll w;
node(int _x,ll _w)
{
x=_x;
w=_w;
}
};
vector<node>a[maxn];
int n;
ll m,dp[maxn],dpf[maxn];
void dfs(int u,int fa)
{
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i].x;
if(v==fa) continue;
dfs(v,u);
dp[u]=max(dp[u],dp[v]+a[u][i].w);
}
}
void DFS(int u,int fa)
{
ll tmp1=0,tmp2=0;
int x,y;
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i].x;
if(v==fa) continue;
if(tmp2<dp[v]+a[u][i].w)
{
tmp2=dp[v]+a[u][i].w;
y=v;
if(tmp1<tmp2)
{
swap(tmp1,tmp2);
swap(x,y);
}
}
}
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i].x;
ll w=a[u][i].w;
if(v==fa) continue;
if(v==x)
dpf[v]=max(dpf[u],tmp2)+w;
else dpf[v]=max(dpf[u],tmp1)+w;
DFS(v,u);
}
}
ll c[maxn],q[maxn],p[maxn];
int main()
{
///cout << "Hello world!" << endl;
///freopen("in.txt","r",stdin);
while(~scanf("%d%lld",&n,&m))
{
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=2;i<=n;i++)
{
int j;ll w;
scanf("%d%lld",&j,&w);
a[j].push_back(node(i,w));
}
memset(dp,0,sizeof dp);
memset(dpf,0,sizeof dpf);
dfs(1,0);
DFS(1,0);
for(int i=1;i<=n;i++)
c[i]=max(dp[i],dpf[i]);
/*-------------------------------*/
//序列为 c
//单调队列求满足max-min<=m的连续子序列最长是多长
int ans=0;
int tail1=0,tail2=0,head1=1,head2=1,pre=1;
for(int i=1;i<=n;i++)
{
while(tail1>=head1&&c[q[tail1]]>=c[i])
tail1--;
q[++tail1]=i;
while(tail2>=head2&&c[p[tail2]]<=c[i])
tail2--;
p[++tail2]=i;
if(c[p[head2]]-c[q[head1]]>m)
{
ans=max(i-pre,ans);
if(q[head1]<p[head2])
{
pre=q[head1]+1;
head1++;
}
else
{
pre=p[head2]+1;
head2++;
}
}
}
ans=max(ans,n+1-pre);//这一句不要掉下
/*-------------------------------*/
printf("%d\n",ans);
}
return 0;
}