HDU 4123 Bob’s Race 树形dp+单调队列
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4123
Memory Limit: 32768/32768 K (Java/Others)
样例输出
1
3
3
3
5
题意
给你一颗树,如果设置的起点包含点v,那么从那里出发的选手就会跑到离它最远的顶点上。现在每个查询给你一个q,让你选最多的起点,同时保证所有选手中跑的最大距离和最小距离要小于等于q。
题解
先用树形dp处理直径的方式处理出每个点能跑的最远距离。然后就是一个裸的单调队列的问题了。(单调队列是可以维护区间最值的),当然,你用rmq或线段树维护也是可以的。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=50505;
int dp[maxn][2],id[maxn];
int arr[maxn];
int n,m;
VPII G[maxn];
///单调队列,用优先队列的t了,手写了一个O(n)的。
struct Queue{
    int lis[maxn],f,r;
    int clk[maxn];
    void init(){ f=1,r=0; }
    bool empty(){ return f>r; }
    void pop_front(){ f++; }
    void pop_back(){ r--; }
    void push(int v,int t){
        lis[++r]=v;
        clk[r]=t;
    }
    int front(int istim){
        if(empty()) return -1;
        if(istim) return clk[f];
        return lis[f];
    }
    int rear(int istim){
        if(istim) return clk[r];
        return lis[r];
    }
}q1,q2;
///树形dp求每个点的最远顶点距离
void dfs(int u,int fa){
    id[u]=-1;
    dp[u][0]=dp[u][1]=0;
    rep(i,0,G[u].sz()){
        int v=G[u][i].X,w=G[u][i].Y;
        if(v==fa) continue;
        dfs(v,u);
        ///更新最大值
        if(dp[u][0]<dp[v][0]+w){
            dp[u][1]=dp[u][0];
            ///更新次大
            dp[u][0]=dp[v][0]+w;
            id[u]=v;
        }else if(dp[u][1]<dp[v][0]+w){
            ///更新次大
            dp[u][1]=dp[v][0]+w;
        }
    }
}
///用父亲下来的最远距离更新最值
void dfs2(int u,int fa,int ma){
    dp[u][0]=max(dp[u][0],ma);
    rep(i,0,G[u].sz()){
        int v=G[u][i].X,w=G[u][i].Y;
        if(v==fa) continue;
        if(id[u]==v){
            dfs2(v,u,max(dp[u][1],ma)+w);
        }else{
            dfs2(v,u,max(dp[u][0],ma)+w);
        }
    }
}
void init(){
    for(int i=1;i<=n;i++) G[i].clear();
}
int main() {
    while(scf("%d%d",&n,&m)==2&&n){
        init();
        rep(i,0,n-1){
            int u,v,w;
            scf("%d%d%d",&u,&v,&w);
            G[u].pb(mkp(v,w));
            G[v].pb(mkp(u,w));
        }
        dfs(1,-1);
        dfs2(1,-1,0);
        for(int i=1;i<=n;i++) arr[i]=dp[i][0];
        while(m--){
            int q; scf("%d",&q);
            ///q1小,q2大,单调队列
            q1.init(),q2.init();
            int l=1,Ma=1;
            for(int i=1;i<=n;i++){
                while(!q1.empty()&&q1.rear(0)>=arr[i]) q1.pop_back();
                while(!q2.empty()&&q2.rear(0)<=arr[i]) q2.pop_back();
                q1.push(arr[i],i);
                q2.push(arr[i],i);
                while(q2.front(0)-q1.front(0)>q){
                    l++;
                    while(q1.front(1)<l) q1.pop_front();
                    while(q2.front(1)<l) q2.pop_front();
                }
                Ma=max(Ma,i-l+1);
            }
            prf("%d\n",Ma);
        }
    }
    return 0;
}
/*
5 3
1 2 9
3 4 5
3 5 3
*/
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号