[BZOJ2500] 幸福的道路

题目描述

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即可 拿出每个点的子树里的点 和根距离的次大值和最大值
第二问双指针+线段树 (单调队列更方便哦)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=1000010;
int n,k,p,q;
int head[maxn],val[maxn<<1],to[maxn<<1],net[maxn<<1];
struct your
{
    long long big;
    long long biger;
    int big_num;
    int biger_num;
}dis[maxn];
long long fasum[maxn];
long long sum[maxn];
int tot;
void add(int x,int y,int c)
{
    net[++tot]=head[x];
    to[tot]=y;
    val[tot]=c; 
    head[x]=tot;
}
int fa[1000010];
void dfs1(int x)
{   
    for(int i=head[x];i;i=net[i])
    {
        if(to[i]==fa[x]) continue;
        dfs1(to[i]);
        if(dis[x].biger<dis[to[i]].biger+val[i])
        {
            dis[x].big=dis[x].biger;
            dis[x].big_num=dis[x].biger_num;
            dis[x].biger=dis[to[i]].biger+val[i];
            dis[x].biger_num=to[i];
            continue;
        }
        if(dis[x].big<dis[to[i]].biger+val[i])
        {
            dis[x].big=dis[to[i]].biger+val[i];
            dis[x].big_num=to[i];
        }
    }
}
long long check(int x,int temp,int c)
{
    long long tmp=fasum[temp];
    if(tmp<dis[temp].biger&&dis[temp].biger_num!=x)
        tmp=dis[temp].biger;
    if(tmp<dis[temp].big&&dis[temp].big_num!=x)
        tmp=dis[temp].big;
    return tmp+c;
}
void dfs2(int x,int c)
{
    fasum[x]=check(x,fa[x],c);
    for(int i=head[x];i;i=net[i])
    {
        if(to[i]==fa[x]) continue;
        dfs2(to[i],val[i]);
    }
    return ;
}
struct tree
{
    int x,y;
    long long maxx,minn,sum;
}a[maxn<<2];
void build(int dx,int dy,int num)
{
    a[num].x=dx,a[num].y=dy;
    if(dx==dy)
    {
        a[num].maxx=sum[dx];
        a[num].minn=sum[dx];
        return ;
    }
    a[num].minn=0x7f7f7f7f;
    int mid=(dx+dy)>>1;
    build(dx,mid,num<<1);
    build(mid+1,dy,num<<1|1);
    a[num].maxx=max(a[num<<1].maxx,a[num<<1|1].maxx);
    a[num].minn=min(a[num<<1].minn,a[num<<1|1].minn);
    return ;
}
long long getmin(int dx,int dy,int num)
{
    if(dx==a[num].x&&dy==a[num].y)
        return a[num].minn;
    int mid=(a[num].x+a[num].y)>>1;
    if(dx>mid) return getmin(dx,dy,num<<1|1);
    if(dy<=mid) return getmin(dx,dy,num<<1);
    return min(getmin(dx,mid,num<<1),getmin(mid+1,dy,num<<1|1));
}
long long getmax(int dx,int dy,int num)
{
    if(dx==a[num].x&&dy==a[num].y)
        return a[num].maxx;
    int mid=(a[num].x+a[num].y)>>1;
    if(dx>mid) return getmax(dx,dy,num<<1|1);
    if(dy<=mid) return getmax(dx,dy,num<<1);
    return max(getmax(dx,mid,num<<1),getmax(mid+1,dy,num<<1|1));
}
struct make
{
    long long sum,c;
};
void work()
{
    int l=1,r=0;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        r++;
        int tmp;
        tmp=getmax(l,r,1)-getmin(l,r,1);
        if(tmp<=k) ans=max(ans,r-l+1);
        else
        {
            while(l<r&&tmp>k)
            {
                l++;
                tmp=getmax(l,r,1)-getmin(l,r,1);
            }
            if(tmp<=k) ans=max(ans,r-l+1);
        }
    }
    printf("%d",ans);
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=2;i<=n;i++)
    {
        int c;
        scanf("%d%d",&fa[i],&c);
        add(fa[i],i,c);
    }
    dfs1(1),dfs2(1,0);
    for(int i=1;i<=n;i++)
        sum[i]=max(fasum[i],dis[i].biger);
    build(1,n,1);
    work();
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注