hdu 4123 树的最长路+RMQ

 

Bob’s Race

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3034    Accepted Submission(s): 991

Problem 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

 

 

树的最长路:

用搜索的方法求某个点的最远的点的距离了,就是先对任意一个点求距离其最远的顶点,最后可以得到一条树的直径的两个端点,以这两个端点开始去遍历整棵树,两个端点到每个点的距离较大值就会是这个点在树上能够走的最远距离


/*
hdu4123
给你n个点,被n-1条边连着,求出以他们每个点为起点的最长路(不可重复走),
然后是m个查询,找出它们的最长连续串max-min<q
树的最长路 + RMQ
hhh-2016-01-31 03:04:55
*/

#include <functional>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <Map>
using namespace std;
typedef long long ll;
typedef long double ld;

using namespace std;

const int maxn = 50005;

ll dp1[maxn][20];
ll dp2[maxn][20];
int mm[maxn+5];
ll sum[maxn];
int tot;
int head[maxn];

ll min(ll a,ll b)
{
    return a < b ? a:b;
}

ll max(ll a,ll b)
{
    return a > b ? a:b;
}

struct node
{
    int to,next;
    ll w;
} edge[maxn*2];

void addedge(int u,int v,int w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void iniRMQ(int n,ll c[])
{
    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]=dp2[i][0]= c[i];
    }
    for(int j = 1; j <= mm[n]; j++)
    {
        for(int i = 1; i+(1<<j)-1 <= n; i++)
        {
            dp1[i][j] = min(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]);
            dp2[i][j] = max(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]);
        }
    }
}

ll RMQ(int x,int y)
{
    int k = mm[y-x+1];
    return (ll)max(dp2[x][k],dp2[y-(1<<k)+1][k])-(ll)min(dp1[x][k],dp1[y-(1<<k)+1][k]);
}
int id;
ll tall;

void dfs(int u,int pre,ll cnt)    //先找出最远点
{
    if(cnt >= tall)
    {
        id = u;
        tall = cnt;
    }
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        if(edge[i].to == pre) continue;
        dfs(edge[i].to,u,edge[i].w+cnt);
    }
}

void cal(int u,int pre,ll cnt)
{
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre)
            continue;
        sum[v] = max(sum[v],cnt+edge[i].w);
        cal(v,u,cnt+edge[i].w);
    }
}

int main()
{
    int m,n,k;
    while(scanf("%d%d",&n,&m) && n && m)
    {
        int u,v,val;
        tot = 0;
        memset(head,-1,sizeof(head));
        memset(sum,0,sizeof(sum));
        for(int i = 1; i < n; i++)
        {
            scanf("%d%d%d",&u,&v,&val);
            addedge(u,v,val);
            addedge(v,u,val);
        }
        tall = 0;
        dfs(1,0,0);
        cal(id,0,0);
        int t = 1;
        for(int i = 1;i <= n;i++)
            if(sum[i] > sum[t]) t = i;
//        printf("%d %d\n",id,t);
        cal(t,0,0);
//        for(int i = 1;i <= n;i++)
//            printf("%d ",sum[i]);
//        cout << endl;
        iniRMQ(n,sum);
        while(m--)
        {
            scanf("%d",&k);
            int ans = 0;
            int td = 1;
            for(int i = 1;i <= n;i++)
            {
                while(td <= i && RMQ(td,i) > k) td++;
                ans = max(ans,i-td+1);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/Przz/p/5409632.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值