题目:BZOJ1999.
题目大意:定义一条路径到一个点的距离为一条路径中距离这个点最近的一个点到这个点的距离,一条路径的偏心距为一个距离这条路径最远的点到这条路径的距离.给定一棵
n
n
n个点的树,求在这棵树的一条直径上的两个点连成一条路径
F
F
F,使得
F
F
F的长度不超过
s
s
s且偏心距最短,输出这个最短的偏心距.
1
≤
n
≤
5
∗
1
0
5
,
0
≤
s
<
2
31
1\leq n\leq 5*10^5,0\leq s<2^{31}
1≤n≤5∗105,0≤s<231,
0
≤
0\leq
0≤所有权值
<
500
<500
<500.
首先根据题目,我们先把直径跑出来,先预处理出直径上每一个点不经过直径上的点可以到达最远的点的距离 d i s [ i ] dis[i] dis[i],容易发现此时直径的偏心距就是 d i s [ i ] dis[i] dis[i]中最大的.
然后把直径列成一条链,把第 i i i个点不经过直径上 i i i后面的点可以到达最远的点的距离 p d [ i ] pd[i] pd[i]和不经过 i i i前面点的最远距离 s d [ i ] sd[i] sd[i]求出来.
之后考虑用双指针枚举路径 F F F对应在直径上的区间 [ l , r ] [l,r] [l,r],枚举左端点 l l l的时候让 r r r尽量大(显然这样更优),然后取 p d [ l ] , max i = l + 1 r − 1 { d i s [ i ] } , s d [ r ] pd[l],\max_{i=l+1}^{r-1}\{dis[i]\},sd[r] pd[l],maxi=l+1r−1{dis[i]},sd[r]中的最大值就是当前路径 F F F的偏心距,用单调队列即可维护.
不过事实上没什么必要,因为很显然 d i s [ i ] ≤ p d [ i ] dis[i]\leq pd[i] dis[i]≤pd[i],所以我们只需要存一个变量就可以得到 p d [ l ] , max i = l + 1 r − 1 { d i s [ i ] } pd[l],\max_{i=l+1}^{r-1}\{dis[i]\} pd[l],maxi=l+1r−1{dis[i]}的最大值了.
时间复杂度 O ( n ) O(n) O(n).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=500000,INF=(1<<30)-1;
int n,m;
struct side{
int y,next,v;
}e[N*2+9];
int lin[N+9],cs;
void Ins(int x,int y,int v){e[++cs].y=y;e[cs].v=v;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y,int v){Ins(x,y,v);Ins(y,x,v);}
int dp[N+9][2],pre[N+9][2];
void Update(int k,int id){
int v=dp[e[id].y][0]+e[id].v;
if (v>dp[k][0]){
dp[k][1]=dp[k][0];pre[k][1]=pre[k][0];
dp[k][0]=v;pre[k][0]=id;
}else if (v>dp[k][1]) dp[k][1]=v,pre[k][1]=id;
}
void Dfs_dp(int k,int fa){
dp[k][0]=0;dp[k][1]=-INF;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa){
Dfs_dp(e[i].y,k);
Update(k,i);
}
}
int dia[N+9],v[N+9],cd;
void Get_dia(){
Dfs_dp(1,0);
int mx=1;
for (int i=1;i<=n;++i)
if (dp[i][0]+dp[i][1]>dp[mx][0]+dp[mx][1]) mx=i;
int k=mx;
for (;k;k=e[pre[k][0]].y) dia[++cd]=k,v[cd]=e[pre[k][0]].v;
reverse(dia+1,dia+cd+1);
reverse(v+1,v+cd+1);
v[cd+1]=e[pre[mx][1]].v;
for (k=e[pre[mx][1]].y;k;k=e[pre[k][0]].y) dia[++cd]=k,v[cd+1]=e[pre[k][0]].v;
}
int dis[N+9],vis[N+9];
void Dfs_dis(int k,int id,int vd){
vis[k]=1;
dis[id]=max(dis[id],vd);
for (int i=lin[k];i;i=e[i].next)
if (!vis[e[i].y]) Dfs_dis(e[i].y,id,vd+e[i].v);
}
int pd[N+9],sd[N+9];
void Get_dis(){
for (int i=1;i<=cd;++i) vis[dia[i]]=1,dis[i]=0;
for (int i=1;i<=cd;++i){
Dfs_dis(dia[i],i,0);
pd[i]=max(dis[i],pd[i-1]+v[i]);
}
for (int i=cd;i>=1;--i) sd[i]=max(sd[i],sd[i+1]+v[i+1]);
}
int ans;
void Get_ans(){
int l=0,r=0,sum=0,now=0;
ans=INF;
for (;l<cd;){
sum-=v[++l];now=max(now,pd[l]);
for (;r<cd&&sum<=m-v[r+1];++r) sum+=v[r+1],now=max(now,dis[r]);
ans=min(ans,max(now,sd[r]));
}
}
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i){
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
Ins2(x,y,v);
}
}
Abigail work(){
Get_dia();
Get_dis();
Get_ans();
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}