首页 > 代码库 > hdu 4123 Bob’s Race (树的直径相关+rmq+单调队列思想)

hdu 4123 Bob’s Race (树的直径相关+rmq+单调队列思想)

Bob’s Race

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


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
 

Source
2011 Asia Fuzhou Regional Contest
 

题意:
先求遍树上的每个点i,能走的最远距离记录为val[i],然后有m个询问,每次询问一个q,求一个最大值减最小值不超过q的最长连续区间。

思路:
先求树的直径两个端点,然后求出每个点到这两个点的距离,有一个结论为点到树上的最远点必为两个端点之一(如果不是的话,那么直径就要换了,反证法),根据此性质求出val数组。
对于每一个询问,扫描一遍,假设j>i,那么以j结尾的最长连续区间的起点必定不小于i的起点(显然),根据这个单调性质,可以用单调队列的思想处理起点,结尾的点枚举即可,判断一个区间内的点是否满足max-min<=q就是用rmq来解决了。
ps:rmq最好预处理lg数组,单调队列只是+n的复杂度。

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 50005
#define MAXN 100005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

int n,m,ans,cnt,tot,flag;
int len,st,ed;   // 直径 起点 终点
bool vis[maxn];
int head[maxn],val[maxn],dist[maxn][2];
int f[maxn][20],g[maxn][20],lg[maxn];  //第二维为二进制
struct Node
{
    int v,w,next;
} edge[MAXN];

void addedge(int u,int v,int w)
{
    cnt++;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa,int sum)
{
    if(sum>len){ len=sum;st=u; }
    int i,j,v;
    for(i=head[u];i;i=edge[i].next)
    {
        v=edge[i].v;
        if(v!=fa)
        {
            dfs(v,u,sum+edge[i].w);
        }
    }
}
void dfs1(int u,int fa,int k,int sum)
{
    dist[u][k]=sum;
    int i,j,v;
    for(i=head[u];i;i=edge[i].next)
    {
        v=edge[i].v;
        if(v!=fa) dfs1(v,u,k,sum+edge[i].w);
    }
}
void init_rmq()              // 预处理  O(n*log(n))
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        f[i][0]=g[i][0]=val[i];
    }
    for(j=1;(1<<j)<=n;j++)
    {
        for(i=1;i+j-1<=n;i++)
        {
            if((i+(1<<(j-1))<=n))
            {
                f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);  //避免越界
                g[i][j]=min(g[i][j-1],g[i+(1<<(j-1))][j-1]);
            }
            else
            {
                f[i][j]=f[i][j-1];
                g[i][j]=g[i][j-1];
            }
        }
    }
}
int query_rmq(int l,int r)
{
    int k=lg[r-l+1];
    return max(f[l][k],f[r-(1<<k)+1][k])-min(g[l][k],g[r-(1<<k)+1][k]);
}
int main()
{
    int i,j,t;
    lg[1]=0;
    for(i=2;i<=50000;i++)
    {
        lg[i]=lg[i>>1]+1;
    }
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break ;
        cnt=0;
        memset(head,0,sizeof(head));
        int u,v,w;
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        len=0;
        dfs(1,0,0);
        ed=st;
        len=0;
        dfs(st,0,0);
        dfs1(st,0,0,0);
        dfs1(ed,0,1,0);
        for(i=1;i<=n;i++)
        {
            val[i]=max(dist[i][0],dist[i][1]);
 //           printf("i:%d val:%d\n",i,val[i]);
        }
        init_rmq();
        int q,le,ri,mid,res,id;
        while(m--)
        {
            scanf("%d",&q);
            ans=id=1;
            for(i=1;i<=n;i++)
            {
                while(id<=i)
                {
                    res=query_rmq(id,i);
                    if(res>q) id++;
                    else break ;
                }
                ans=max(ans,i-id+1);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}