Description
某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000)。
这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。
现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。
你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。
题解:
好题啊!显然这条路径在树的直径上,然后维护一个单调队列,然后用两个指针,表示现在是那一段路径,单调队列用来维护路径上的点到非直径上的点的最长距离,而到直径上的点的距离是可以直接用前缀和相减算出来的。代码奇丑奇慢,建议不要抄。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=300010;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
struct Edge{int y,d,next;}e[Maxn*2];
int last[Maxn],len=0;
void ins(int x,int y,int d)
{
int t=++len;
e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;
}
int n,s,fa[Maxn];
void dfs(int x,int f)
{
fa[x]=f;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y!=f)dfs(y,x);
}
}
int ans,p,st,ed,Next[Maxn],f[Maxn],ff[Maxn],q[Maxn];
bool vis[Maxn];
void work(int x,int t)
{
vis[x]=true;
if(t>ans){ans=t;p=x;}
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(!vis[y])work(y,t+e[i].d);
}
}
map<int,map<int,int> >dis;
int main()
{
n=read();s=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read(),d=read();
ins(x,y,d);ins(y,x,d);
dis[x][y]=dis[y][x]=d;
}
dfs(1,1);
memset(vis,false,sizeof(vis));ans=0;work(1,0);st=p;
memset(vis,false,sizeof(vis));ans=0;work(p,0);ed=p;
memset(vis,false,sizeof(vis));
int x=st,lca;
vis[x]=true;
while(x!=1)Next[x]=fa[x],vis[x=fa[x]]=true;
x=ed;
while(!vis[x])Next[fa[x]]=x,x=fa[x];
lca=x;
x=st;f[st]=0;
while(x!=ed)
{
f[Next[x]]=f[x]+dis[x][Next[x]];
x=Next[x];
}
memset(vis,false,sizeof(vis));
x=st;vis[st]=true;
while(Next[x]!=ed)vis[x=Next[x]]=true;
vis[ed]=true;
x=st;ans=0;work(st,0);ff[st]=ans;
while(Next[x]!=ed)
{
x=Next[x];
ans=0;work(x,0);ff[x]=ans;
}
ans=0;work(ed,0);ff[ed]=ans;
int head=st,tail=st,tot=0,Ans=f[ed],l=1,r=0;
while(1)
{
while(tail!=ed&&tot+dis[tail][Next[tail]]<=s)
{
while(l<=r&&ff[q[r]]<=ff[tail])r--;
q[++r]=tail;
tot+=dis[tail][Next[tail]],tail=Next[tail];
}
Ans=min(Ans,max(max(f[head]-f[st],f[ed]-f[tail]),ff[q[l]]));
if(tail==ed)break;
tot-=dis[head][Next[head]];head=Next[head];
if(q[l]<=head)l++;
}
printf("%d",Ans);
}