HDU 4123 Bob’s Race 树的直径+单调队列

题意:

给定n个点的带边权树Q个询问。

下面n-1行给出树

下面Q行每行一个数字表示询问。

首先求出dp[N] :dp[i]表示i点距离树上最远点的距离

询问u, 表示求出 dp 数组中最长的连续序列使得序列中最大值-最小值 <= u,输出这个序列的长度。

思路:

求dp数组就是求个树的直径然后dfs一下。

对于每个询问,可以用一个单调队列维护一下。O(n)的回答。

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
typedef long long ll;
const int N = 50010;
int n, Q;
struct Edge{
    int to, nex;   ll dis;
}edge[N<<1];
struct node {
    int v, id;
    node() {}
    node(int _id, int _v) {
        id = _id; v = _v;
    }
};
int head[N], edgenum;
void init(){for(int i = 1; i <= n; i++)head[i] = -1; edgenum = 0;}
void add(int u, int v, ll d){
    Edge E = {v, head[u], d};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
ll dis[N], dp[N], len;
int Stack[N], top, pre[N], vis[N];
int BFS(int x){
    for(int i = 1; i <= n; i++)
        dis[i] = -1;
    dis[x] = 0; pre[x] = -1;
    int far = x;
    queue<int> q; q.push(x);
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = head[u]; ~i; i = edge[i].nex){
            int v = edge[i].to;
            if(dis[v] == -1)
            {
                dis[v] = dis[u] + edge[i].dis;
                pre[v] = u;
                if(dis[far] < dis[v])
                    far = v;
                q.push(v);
            }
        }
    }
    return far;
}
void dfs(int u){
    vis[u] = 1;
    for(int i = head[u]; ~i; i = edge[i].nex)
    {
        int v = edge[i].to;
        if(vis[v])continue;
        dp[v] = dp[u] + edge[i].dis;
        dfs(v);
    }
}
void build(){//预处理树的直径
    int E = BFS(1);
    int S = BFS(E);
    top = 0;
    int u = S;
    len = dis[S];
    for(int i = 1; i <= n; i++) vis[i] = 0;
    while(u!=-1)
    {
        Stack[top++] = u;
        dp[u] = max(dis[u], len - dis[u]);
        vis[u] = 1;
        u = pre[u];
    }
    for(int i = 0; i < top; i++)     dfs(Stack[i]);
}
void input(){
    init();  ll d;
    for(int i = 1, u, v; i < n; i++)
    {
        rd(u); rd(v); rd(d);
        add(u, v, d); add(v, u, d);
    }
}

node mx[N], mi[N];
int h1, t1, h2, t2;
int main() {
    int v, idx, ans;
	while(cin>>n>>Q, n+Q) {
		input();
		build();
		while(Q--)
        {
            rd(v);
            ans = h1 = t1 = h2 = t2 = 0;
            idx = 1;
            for (int i = 1; i <= n; ++i) {
                while (h1!=t1 && mx[t1-1].v <= dp[i])
                    -- t1;
                mx[t1++] = node(i, dp[i]);
                while (h2!=t2 && mi[t2-1].v >= dp[i])
                    -- t2;
                mi[t2++] = node(i, dp[i]);
                while (h1!=t1&&h2!=t2) {
                    if (mx[h1].v-mi[h2].v>v)
                        ++ idx;
                    else
                        break;
                    while (h1!=t1&&mx[h1].id<idx)
                        ++h1;
                    while (h2!=t2&&mi[h2].id<idx)
                        ++h2;
                }
                ans = max(ans, i-idx+1);
            }
            pt(ans);
            putchar('\n');
        }
	}
	return 0;
}
时间: 2024-10-12 04:48:56

HDU 4123 Bob’s Race 树的直径+单调队列的相关文章

hdu 4123 Bob’s Race 树的直径+rmq+尺取

Bob’s Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 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

POJ 3162 Walking Race(树的直径+单调队列)

题目大意:对一棵树,求出从每个结点出发能到走的最长距离(每个结点最多只能经过一次),将这些距离按排成一个数组得到dis[1],dis[2],dis[3]……dis[n] ,在数列的dis中求一个最长的区间,使得区间中的最大值与最小值的差不超过m. 思路:先找出树的直径的两个端点来,那么树当中的其它节点能走的最大距离一定是到这个两个点当中的其中一个的.所以三遍bfs就可以求出来这个最远的距离,那么,这个最远的距离求出来之后再用两个单调队列来维护最大值和最小值. /*****************

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

HDU 4123 Bob&#39;s Race:单调队列 + st表

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[i]为:从节点i出发,不重复经过节点,所能够走的最远距离. 每次询问问你:区间[l,r]最长能有多长,同时保证 max{dis[i]} - min{dis[i]} <= q (i∈[l,r]) 题解: 首先有一个结论: 从树上的任意一个节点出发,尽可能往远走,最终一定会到达树的直径的两个端点之一.

hdu 4123 Bob’s Race(树形dp+RMQ)

题目链接:hdu 4123 Bob's Race 题目大意:一个城镇有N个住户,N-1条路连接两个住户,保证N个住户联通,M次询问,给定N条边的信息,包括连 接的住户序号以及路的长度.然后是M次询问,每次询问Q,要求找到最长的连续序号,使得Max(dis[i]) - Min(dis[i]) ≤ Q(l≤i≤r),输出最大的r-l+1.dis[i]为从第i个住户出发,不重复走过路能移动的最远距离. 解题思路:树形dp,通过两次dfs,第1次处理出每个节点中孩子节点移动的最长距离和第二长距离,第2次

HDU 4123 Bob’s Race

Bob’s Race Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=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

HDU 4123(树的直径+单调队列)

Bob’s Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2833    Accepted Submission(s): 917 Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble i

HDU 4123 Bob’s Race(RMQ)

题意是说给出一棵树,N(10^5)个顶点,以及每条边的权值,现在需要选择连续的K个点(顶点编号连续),可以被选出来的条件是: 若d[i]代表顶点i到树上其他点的距离的最大值,使得区间[a, b]的d值的最大差值不大于Q, 也就是max(d[a], d[a + 1], ..., d[b]) - max(d[a], d[a + 1], ..., d[b]) <= Q Q是给出的一个查询(共有m<=500个查询),求对应每一个查询的K的最大值 思路是首先预处理出每个点到其他点的最大距离, 这可以通过

[noi2013]快餐店 基环树dp,单调队列维护最大值和次大值

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 220000 #define inf 0x3ffffffffffffffLL typedef long long ll; int v[N],e[N],ne[N],nn,w[N]; void add(int x,int y,int z){ ne[++nn