hdoj 4123 Bob’s Race 【树的直径 + RMQ】 【二分查询会超时】

来源:互联网 发布:守望者 知乎 编辑:程序博客网 时间:2024/05/25 19:57

Bob’s Race

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


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 51 2 32 3 44 5 33 4 2123450 0
 

Sample Output
13335
 

大致题意:给出N个点和N-1条边(它们构成一棵树)。每个节点在树中都有最长路,对于 i 节点的最长路我们用A[ i ]来表示,那么我们就得到一个A[ i ] (1 <= i <= N)序列。现在给一个Q,让你在序列A[] 中 找到一个最长的连续区间 使得该区间里面的最大值和最小值之差不超过Q。


设树的直径为 S - T 路径

思路:先利用树的直径求出每个节点的最长路(节点的最长路 要么是它到S的距离 要么是它到T的距离),然后用RMQ预处理区间最大值和最小值,枚举起点更新最值。

这个方法有点慢,看来要学单调队列了。。。

超时代码:二分查找最优区间  醉了。。。

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define MAXN 50000+10#define MAXM 100000+10using namespace std;struct Edge{    int from, to, val, next;};Edge edge[MAXM];int head[MAXN], edgenum;int dist[MAXN];bool vis[MAXN];int N, M;//N个点 M次查询int S, T;//最长路两个端点int d1[MAXN], d2[MAXN];//分别存储最长路两个端点到该点的距离void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, int w){    Edge E = {u, v, w, head[u]};    edge[edgenum] = E;    head[u] = edgenum++;}void getMap(){    int a, b, c;    for(int i = 2; i <= N; i++)    {        scanf("%d%d%d", &a, &b, &c);        addEdge(a, b, c);        addEdge(b, a, c);    }}int BFS(int sx){    queue<int> Q;    memset(dist, 0, sizeof(dist));    memset(vis, false, sizeof(vis));    vis[sx] = true;    int ans = 0;    int node = sx;    Q.push(sx);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(!vis[E.to] && dist[E.to] < dist[u] + E.val)            {                vis[E.to] = true;                dist[E.to] = dist[u] + E.val;                if(dist[E.to] > ans)                {                    ans = dist[E.to];                    node = E.to;                }                Q.push(E.to);            }        }    }    return node;}//RMQ求满足 最大值最小值之差不大于Q的 最大区间int A[MAXN];//存储每个点的最长路int Amax[MAXN][30];int Amin[MAXN][30];void RMQ_init()//预处理区间 最大值 最小值{    for(int i = 1; i <= N; i++)        Amax[i][0] = Amin[i][0] = A[i];    for(int j = 1; (1<<j) <= N; j++)    {        for(int i = 1; i + (1<<j) - 1 <= N; i++)        {            Amax[i][j] = max(Amax[i][j-1], Amax[i + (1<<(j-1))][j-1]);            Amin[i][j] = min(Amin[i][j-1], Amin[i + (1<<(j-1))][j-1]);        }    }}int query(int L, int R)//求区间[L, R]最大值最小值 之差{    int k = 0;    while(1<<(k+1) <= R-L+1) k++;    return max(Amax[L][k], Amax[R-(1<<k) + 1][k]) - min(Amin[L][k], Amin[R-(1<<k) + 1][k]);}void solve(){    S = BFS(1);//找到一个端点    T = BFS(S);//以找到的端点为起点 找另一个端点    //printf("%d\n", T);    for(int i = 1; i <= N; i++)        d1[i] = dist[i];//S为起点 到各点的最长路    BFS(T);//以另一个端点为起点    for(int i = 1; i <= N; i++)    {        d2[i] = dist[i];//T为起点 到各点的最长路        A[i] = max(d1[i], d2[i]);    }    RMQ_init();//RMQ预处理    int Q;    while(M--)    {        scanf("%d", &Q);        int ans = 0;        for(int i = 1; i <= N; i++)        {            //二分查找最优区间            //只是终止条件 和 区间更替不太一样            int left = i, right = N, mid;            while(right - left > 1)            {                mid = (left + right) >> 1;                if(query(i, mid) > Q)                    right = mid;                else                    left = mid;            }            if(query(i, right) <= Q)                ans = max(ans, right - i + 1);            else                ans = max(ans, left - i + 1);        }        printf("%d\n", ans);    }}int main(){    while(scanf("%d%d", &N, &M), N||M)    {        init();        getMap();        solve();    }    return 0;}



AC代码: 

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define MAXN 50000+10#define MAXM 100000+10using namespace std;struct Edge{    int from, to, val, next;};Edge edge[MAXM];int head[MAXN], edgenum;int dist[MAXN];bool vis[MAXN];int N, M;//N个点 M次查询int S, T;//最长路两个端点int d1[MAXN], d2[MAXN];//分别存储最长路两个端点到该点的距离void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, int w){    Edge E = {u, v, w, head[u]};    edge[edgenum] = E;    head[u] = edgenum++;}void getMap(){    int a, b, c;    for(int i = 2; i <= N; i++)    {        scanf("%d%d%d", &a, &b, &c);        addEdge(a, b, c);        addEdge(b, a, c);    }}int BFS(int sx){    queue<int> Q;    memset(dist, 0, sizeof(dist));    memset(vis, false, sizeof(vis));    vis[sx] = true;    int ans = 0;    int node = sx;    Q.push(sx);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(!vis[E.to] && dist[E.to] < dist[u] + E.val)            {                vis[E.to] = true;                dist[E.to] = dist[u] + E.val;                if(dist[E.to] > ans)                {                    ans = dist[E.to];                    node = E.to;                }                Q.push(E.to);            }        }    }    return node;}//RMQ求满足 最大值最小值之差不大于Q的 最大区间int A[MAXN];//存储每个点的最长路int Amax[MAXN][30];int Amin[MAXN][30];void RMQ_init()//预处理区间 最大值 最小值{    for(int i = 1; i <= N; i++)        Amax[i][0] = Amin[i][0] = A[i];    for(int j = 1; (1<<j) <= N; j++)    {        for(int i = 1; i + (1<<j) - 1 <= N; i++)        {            Amax[i][j] = max(Amax[i][j-1], Amax[i + (1<<(j-1))][j-1]);            Amin[i][j] = min(Amin[i][j-1], Amin[i + (1<<(j-1))][j-1]);        }    }}int query(int L, int R)//求区间[L, R]最大值最小值 之差{    int k = 0;    while(1<<(k+1) <= R-L+1) k++;    return max(Amax[L][k], Amax[R-(1<<k) + 1][k]) - min(Amin[L][k], Amin[R-(1<<k) + 1][k]);}void solve(){    S = BFS(1);//找到一个端点    T = BFS(S);//以找到的端点为起点 找另一个端点    //printf("%d\n", T);    for(int i = 1; i <= N; i++)        d1[i] = dist[i];//S为起点 到各点的最长路    BFS(T);//以另一个端点为起点    for(int i = 1; i <= N; i++)    {        d2[i] = dist[i];//T为起点 到各点的最长路        A[i] = max(d1[i], d2[i]);    }    RMQ_init();//RMQ预处理    int Q;    while(M--)    {        scanf("%d", &Q);        int ans = 1;        int s = 1;        for(int i = 1; i <= N; i++)        {            while(query(s, i) > Q && s < i)                s++;            ans = max(ans, i - s + 1);        }        printf("%d\n", ans);    }}int main(){    while(scanf("%d%d", &N, &M), N||M)    {        init();        getMap();        solve();    }    return 0;}



0 0
原创粉丝点击