zoukankan      html  css  js  c++  java
  • 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('
    ');
            }
    	}
    	return 0;
    }
    

  • 相关阅读:
    leetcode-----118. 杨辉三角
    leetcode-----117. 填充每个节点的下一个右侧节点指针 II
    leetcode-----116. 填充每个节点的下一个右侧节点指针
    leetcode-----115. 不同的子序列
    leetcode-----114. 二叉树展开为链表
    leetcode-----113. 路径总和 II
    leetcode-----112. 路径总和
    leetcode-----111. 二叉树的最小深度
    windows同时安装jdk7和jdk8
    使用乌龟Git连接github
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4544043.html
Copyright © 2011-2022 走看看