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
*/