zoukankan      html  css  js  c++  java
  • (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列

    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

    HINT

    数据范围:
    50%的数据N<=1000
    80%的数据N<=100000
    100%的数据N<=1000000

    题解:

    其实这题很水……全场切掉,但是自己很少写单调队列(几乎没写过),所以调了很久最后发现了数个傻逼错……搞了很久才对……

    首先这题是树形DP+单调队列二合一,前半部分直接DP,设$F[i]$表示以$i$为根的子树里最长的距离,$G[i]$表示从$i$向上走到一个祖先再向下的最大值,直接两次dfs处理(转移的时候要记录一个次大值)。那么最大的幸福值就是$max(F[i],G[i])$;

    后半部分注意到可选的区间是连续的,所以左右端点必定严格从左向右移动,所以可以用单调队列来维护,开两个单调队列维护区间最大最小值,记录当前区间大小即可(我也不知道我为什么能写出那么多傻逼错)

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<queue>
     6 using namespace std;
     7 struct edge{
     8     int v,w,next;
     9 }a[1000001];
    10 int n,m,x,w,tot=0,ans=0,tmp=1,head[1000001],num[1000001],f[1000001],ff[1000001],g[1000001];
    11 //queue<int>ql,qr;
    12 int ql[1000001],qr[1000001],l1=0,l2=0,r1=-1,r2=-1;
    13 void add(int u,int v,int w){
    14     a[++tot].v=v;
    15     a[tot].w=w;
    16     a[tot].next=head[u];
    17     head[u]=tot;
    18 }
    19 void dfs1(int u){
    20     f[u]=ff[u]=0;
    21     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
    22         int v=a[tmp].v,w=a[tmp].w;
    23         dfs1(v);
    24         if(f[v]+w>f[u]){
    25             ff[u]=f[u];
    26             f[u]=f[v]+w;
    27         }else if(f[v]+w>ff[u]){
    28             ff[u]=f[v]+w;
    29         }
    30     }
    31 }
    32 void dfs2(int u){
    33     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
    34         int v=a[tmp].v,w=a[tmp].w;
    35         g[v]=g[u]+w;
    36         if(f[v]+w==f[u])g[v]=max(g[v],ff[u]+w);
    37         else g[v]=max(g[v],f[u]+w);
    38         dfs2(v);
    39     }
    40 }
    41 int main(){
    42     memset(head,-1,sizeof(head));
    43     scanf("%d%d",&n,&m);
    44     for(int i=2;i<=n;i++){
    45         scanf("%d%d",&x,&w);
    46         add(x,i,w);
    47     }
    48     dfs1(1);
    49     dfs2(1);
    50     for(int i=1;i<=n;i++)num[i]=max(f[i],g[i]);
    51     for(int i=1;i<=n;i++){
    52         while(l1<=r1&&num[i]<=num[ql[r1]])r1--;
    53         ql[++r1]=i;
    54         while(l2<=r2&&num[i]>=num[qr[r2]])r2--;
    55         qr[++r2]=i;
    56         while(num[qr[l2]]-num[ql[l1]]>m){
    57             tmp=ql[l1]<qr[l2]?ql[l1++]+1:qr[l2++]+1;
    58         }
    59         ans=max(ans,i-tmp+1);
    60     }
    61     printf("%d",ans);
    62     return 0;
    63 }
  • 相关阅读:
    IntelliJ IDEA教程之如何clean或者install Maven项目
    mysql 导出表,导出数据 命令
    import require
    https确实加密了。 抓包是一个中间人攻击过程
    密码学部分算法
    账号密码加密的方案
    查看git提交细节
    使用源安装java JDK
    updated stream stash changes
    Hibernate与Jpa的关系
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9443001.html
Copyright © 2011-2022 走看看