http://poj.org/problem?id=3162

题意:
一棵n个节点的树。有一个屌丝爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要在这n个距离里取连续的若干天,使得这些天里最大距离和最小距离的差小于M,问怎么取使得天数最多?

 

思路:
这道题目求最远距离和HDU 2196是一模一样的,这个不是很难。关键是要怎么处理得到的数据。

可以用单调队列做也可以用线段树来做,先介绍一下单调队列。

因为有最大值和最小值,所以我们需要两个单调队列,一个维护最大值,另一个维护最小值。

POJ 3162 Walking Race(树形dp+单调队列 or 线段树)

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,ll> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn=1e6+5;
 17 
 18 int n, m;
 19 int tot;
 20 ll d[maxn][3];
 21 int path[maxn];
 22 int head[2*maxn];
 23 int q_max[maxn];
 24 int q_min[maxn];
 25 
 26 struct node
 27 {
 28     int v,w,next;
 29 }e[2*maxn];
 30 
 31 void addEdge(int u,int v,int w)
 32 {
 33     e[tot].v=v;
 34     e[tot].w=w;
 35     e[tot].next=head[u];
 36     head[u]=tot++;
 37 }
 38 
 39 void dfs1(int u,int fa)
 40 {
 41     d[u][0]=d[u][1]=0;
 42     path[u]=-1;
 43     for(int i=head[u];i!=-1;i=e[i].next)
 44     {
 45         int v=e[i].v;
 46         if(v==fa)  continue;
 47         dfs1(v,u);
 48         if(d[u][0]<d[v][0]+e[i].w)
 49         {
 50             path[u]=v;
 51             d[u][1]=d[u][0];
 52             d[u][0]=d[v][0]+e[i].w;
 53         }
 54         else if(d[u][1]<d[v][0]+e[i].w)
 55             d[u][1]=d[v][0]+e[i].w;
 56     }
 57 }
 58 
 59 void dfs2(int u,int fa)
 60 {
 61     for(int i=head[u];i!=-1;i=e[i].next)
 62     {
 63         int v=e[i].v;
 64         if(v==fa)  continue;
 65         if(path[u]==v)  d[v][2]=max(d[u][2],d[u][1])+e[i].w;
 66         else  d[v][2]=max(d[u][0],d[u][2])+e[i].w;
 67         dfs2(v,u);
 68     }
 69 }
 70 
 71 int main()
 72 {
 73     //freopen("in.txt","r",stdin);
 74     while(~scanf("%d%d",&n,&m))
 75     {
 76         tot=0;
 77         memset(head,-1,sizeof(head));
 78         for(int i=2;i<=n;i++)
 79         {
 80             int v,w;
 81             scanf("%d%d",&v,&w);
 82             addEdge(i,v,w);
 83             addEdge(v,i,w);
 84         }
 85         dfs1(1,-1);
 86         dfs2(1,-1);
 87         int ans=-1;
 88         int frt_max=1,rear_max=1;
 89         int frt_min=1,rear_min=1;
 90         for(int i=1,j=1;i<=n;i++)
 91         {
 92             d[i][0]=max(d[i][0],d[i][2]);
 93             while(frt_max<rear_max && d[q_max[rear_max-1]][0]<d[i][0])  rear_max--;
 94             q_max[rear_max++]=i;
 95             while(frt_min<rear_min && d[q_min[rear_min-1]][0]>d[i][0])  rear_min--;
 96             q_min[rear_min++]=i;
 97 
 98             while(frt_max<rear_max && frt_min<rear_min && d[q_max[frt_max]][0]-d[q_min[frt_min]][0]>m)
 99             {
100                 if(q_max[frt_max]>q_min[frt_min])   {j=q_min[frt_min]+1;frt_min++;}
101                 else {j=q_max[frt_max]+1;frt_max++;}
102             }
103             ans=max(ans,i-j+1);
104         }
105         printf("%d\n",ans);
106     }
107     return 0;
108 }
单调队列

相关文章: