zoukankan      html  css  js  c++  java
  • 【BZOJ2500】幸福的道路 树形DP+RMQ+双指针法

    【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

    题解:这题显然可以被分成两个子任务

    1.求树上距离点i最远的点到i的距离

    方法:维护每个点子树中到这个点距离的最大值和次大值,然后搞一搞~

    2.求最长的一段区间,使得区间中最大值和最小值的差≤M

    方法:先用RMQ求出区间最大值最小值,然后上双指针法

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=1000010;
    int n,m,cnt,l,r,ans;
    int fa[maxn],to[maxn<<1],next[maxn<<1],head[maxn];
    int d1[maxn],d2[maxn],q[maxn],from[maxn];
    int Log[maxn],dm[maxn][20],dn[maxn][20];
    void updata(int x,int tmp)
    {
        if(d1[x]<tmp)    d2[x]=d1[x],d1[x]=tmp;
        else    d2[x]=max(d2[x],tmp);
    }
    void dfs1(int x)
    {
        int i,tmp;
        q[++q[0]]=x;
        for(i=head[x];i!=-1;i=next[i])
            dfs1(to[i]),updata(x,d1[to[i]]+from[to[i]]);
    }
    void add(int a,int b)
    {
        to[cnt]=b;
        next[cnt]=head[a];
        head[a]=cnt++;
    }
    int gm(int a,int b)
    {
        int k=Log[b-a+1];
        return max(dm[a][k],dm[b-(1<<k)+1][k]);
    }
    int gn(int a,int b)
    {
        int k=Log[b-a+1];
        return min(dn[a][k],dn[b-(1<<k)+1][k]);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int i,j,a,b,c;
        memset(head,-1,sizeof(head));
        for(i=2;i<=n;i++)
        {
            scanf("%d%d",&fa[i],&from[i]);
            add(fa[i],i);
        }
        dfs1(1);
        for(i=2;i<=n;i++)
        {
            if(d1[fa[q[i]]]==d1[q[i]]+from[q[i]])   updata(q[i],d2[fa[q[i]]]+from[q[i]]);
            else    updata(q[i],d1[fa[q[i]]]+from[q[i]]);
        }
        for(i=1;i<=n;i++)    dm[i][0]=dn[i][0]=d1[i];
        for(i=2;i<=n;i++)    Log[i]=Log[i>>1]+1;
        for(j=1;(1<<j)<=n;j++)
        {
            for(i=1;i+(1<<j)-1<=n;i++)
            {
                dm[i][j]=max(dm[i][j-1],dm[i+(1<<j-1)][j-1]);
                dn[i][j]=min(dn[i][j-1],dn[i+(1<<j-1)][j-1]);
            }
        }
        int h=1;
        ans=-1;
        for(i=1;i<=n;i++)
        {
            while(gm(h,i)-gn(h,i)>m) h++;
            ans=max(ans,i-h+1);
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    “XXXXX” is damaged and can’t be opened. You should move it to the Trash 解决方案
    深入浅出 eBPF 安全项目 Tracee
    Unity3d开发的知名大型游戏案例
    Unity 3D 拥有强大的编辑界面
    Unity 3D物理引擎详解
    Unity 3D图形用户界面及常用控件
    Unity 3D的视图与相应的基础操作方法
    Unity Technologies 公司开发的三维游戏制作引擎——Unity 3D
    重学计算机
    windows cmd用户操作,添加,设备管理员组,允许修改密码
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6819604.html
Copyright © 2011-2022 走看看