树形dp--hdu4123

D - Bob’s Race
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit  Status  Practice  HDU 4123

Description

Bob wants to hold a race to encourage people to do sports. He has got trouble in choosing the route. There are N houses and N - 1 roads in his village. Each road connects two houses, and all houses are connected together. To make the race more interesting, he requires that every participant must start from a different house and run AS FAR AS POSSIBLE without passing a road more than once. The distance difference between the one who runs the longest distance and the one who runs the shortest distance is called “race difference” by Bob. Bob does not want the “race difference”to be more than Q. The houses are numbered from 1 to N. Bob wants that the No. of all starting house must be consecutive. He is now asking you for help. He wants to know the maximum number of starting houses he can choose, by other words, the maximum number of people who can take part in his race.
 

Input

There are several test cases. 
The first line of each test case contains two integers N and M. N is the number of houses, M is the number of queries. 
The following N-1 lines, each contains three integers, x, y and z, indicating that there is a road of length z connecting house x and house y. 
The following M lines are the queries. Each line contains an integer Q, asking that at most how many people can take part in Bob’s race according to the above mentioned rules and under the condition that the“race difference”is no more than Q. 

The input ends with N = 0 and M = 0. 

(N<=50000 M<=500 1<=x,y<=N 0<=z<=5000 Q<=10000000) 
 

Output

For each test case, you should output the answer in a line for each query. 
 

Sample Input

      
      
      
      
5 5 1 2 3 2 3 4 4 5 3 3 4 2 1 2 3 4 5 0 0
 

Sample Output

      
      
      
      
1 3 3 3 5
题意:有n村庄,简称点,n-1条边,每条边有一个长度,在k个连续的村庄有k个人参加比赛(k是所要求得),每个人都
向边缘跑,跑的越远越好,每个人跑的最远距离记为Di;然后有Q个询问,每次给出距离差d,在连续的k个村庄中k个人的Di之差不能超过d,求最大的k,我们先求出每个点能跑的最远距离,然后用ST 的RMQ算法计算区间Di的最大值与最小值,最大值与最小值之差小于d那么k个人的Di之差全部小于d,然后用尺取法找最大连续区间,就是我们要求的k:
在这个题中有三的知识点,1,求每个点可达的最远距离;2,RMQ求区间最值;3,尺取求出最大区间k;
在本题中不一一讲解每个知识点,代码中有一些关于知识点1的介绍
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
const int Maxn=50050;
struct Edge
{
    int to,cap,next;
}edge[Maxn*2];
int head[Maxn],tot;
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
    edge[tot].to=v;
    edge[tot].cap=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}

int maxn[Maxn];///距离叶子最远;
int smaxn[Maxn];///相反方向 距离叶子最远的
int maxid[Maxn]; ///指向 走向最远 的方向
int smaxid[Maxn];///与 “指向 走向最远 的方向”这个方向相反的方向
void dfs1(int u,int pre)
{
    maxn[u]=smaxn[u]=maxid[u]=smaxid[u]=0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==pre)continue;
        dfs1(v,u);///深入到树叶然后向上递归
        if(maxn[v]+edge[i].cap>smaxn[u])
        {
            ///此时此刻maxn[v]+edge[i].cap就是maxn[u],但是不管三七二十一了,最后交换去吧
            smaxn[u]=maxn[v]+edge[i].cap;
            smaxid[u]=v;
            if(maxn[u]<smaxn[u])///最后总会交换maxn 和 smaxn,所以每次更新smaxn好了
            {
                swap(maxn[u],smaxn[u]);///交换值
                swap(maxid[u],smaxid[u]);///方向也交换
            }
        }
    }
}
void dfs2(int u,int pre)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==pre)continue;
        if(maxid[u]==v)///u->v 向长的一端跑
        {
             if(smaxn[u] + edge[i].cap > smaxn[v])///更新下一个节点短向的值
            {
                smaxn[v] = smaxn[u] + edge[i].cap;
                smaxid[v] = u;
                if(maxn[v] < smaxn[v])
                {
                    swap(maxn[v],smaxn[v]);
                    swap(maxid[v],smaxid[v]);
                }
            }
        }
        else ///反向  向短的一端跑
        {
           if(maxn[u] + edge[i].cap > maxn[v])
            {
                maxn[v] = maxn[u] + edge[i].cap;
                maxid[v] = u;
                if(maxn[v] < smaxn[v])
                {
                    swap(maxn[v],smaxn[v]);
                    swap(maxid[v],smaxid[v]);
                }
            }
        }
        dfs2(v,u);
    }
}
int a[Maxn];
int dp1[Maxn][20];
int dp2[Maxn][20];
int mm[Maxn];
void initRMQ(int n)
{
    mm[0] = -1;
    for(int i = 1;i <= n;i++)
    {
        mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
        dp1[i][0] = a[i];
        dp2[i][0] = a[i];
    }
    for(int j = 1;j <= mm[n];j++)
        for(int i = 1;i + (1<<j) - 1 <= n;i++)
        {
            dp1[i][j] = max(dp1[i][j-1],dp1[i + (1<<(j-1))][j-1]);
            dp2[i][j] = min(dp2[i][j-1],dp2[i + (1<<(j-1))][j-1]);
        }
}
int rmq(int x,int y)
{
    int k = mm[y-x+1];
    return //min(dp2[x][k],dp2[y-(1<<k)+1][k]);
    max(dp1[x][k],dp1[y-(1<<k)+1][k])- min(dp2[x][k],dp2[y-(1<<k)+1][k]);
}
int main()
{
    int n,m;
    int u,v,w,q;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        if(n==0)
            break;
            init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dfs1(1,1);
        dfs2(1,1);
        for(int i=1;i<=n;i++)
            a[i]=maxn[i];
        initRMQ(n);
        for(int i=0;i<m;i++)
        {
            scanf("%d",&q);
            int ans=0,id=1;
            for(int i=1;i<=n;i++)
            {
                while(id<=i&&rmq(id,i)>q)
                {
                  id++;
                  cout<<rmq(id,i)<<endl;
                }

                ans=max(ans,i-id+1);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}


你可能感兴趣的:(树形dp--hdu4123)