题目背景
公元2044年,人类进入了宇宙纪元。
题目描述
公元2044年,人类进入了宇宙纪元。
L
L
国有个星球,还有
n−1
n
−
1
条双向航道,每条航道建立在两个球之间,这
n−1
n
−
1
条航道连通了
L
L
国的所有星球。
小掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从
ui
u
i
号星球沿最快的宇航路径飞行到
vi
v
i
号星球去。显然,飞船驶过一条航道是需要时间的,对于航道
j
j
,任意飞船驶过它所花费的时间为,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新,
L
L
国国王同意小的物流公司参与
L
L
国的航道建设,即允许小把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小
P
P
的物流公司就预接了个运输计划。在虫洞建设完成后,这
m
m
个运输计划会同时开始,所有飞船一起出发。当这个运输计划都完成时,小
P
P
的物流公司的阶段性工作就完成了。
如果小可以自由选择将哪一条航道改造成虫洞,试求出小
P
P
的物流公司完成阶段性工作所需要的最短时间是多少?
输入输出格式
输入格式:
第一行包括两个正整数,表示 L 国中星球的数量及小 P P 公司预接的运输计划的数量,星球从到 n n 编号。
接下来行描述航道的建设情况,其中第
i
i
行包含三个整数 和
ti
t
i
,表示第
i
i
条双向航道修建在与
bi
b
i
两个星球之间,任意飞船驶过它所花费的时间为
ti
t
i
。数据保证
1≤ai,bi≤n
1
≤
a
i
,
b
i
≤
n
且
0≤ti≤1000
0
≤
t
i
≤
1000
。
接下来
m
m
行描述运输计划的情况,其中第行包含两个正整数
uj
u
j
和
vj
v
j
,表示第
j
j
个运输计划是从号星球飞往
vj
v
j
号星球。
数据保证
1≤ui,vi≤n
1
≤
u
i
,
v
i
≤
n
输出格式:
一个整数,表示小 P P 的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
输入样例#1:
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
输出样例#1:
11
说明
所有测试数据的范围和特点如下表所示
请注意常数因子带来的程序效率上的影响。
分析:先用倍增求出两点之间的距离。然后把距离从大到小排序,枚举位置 i i 表示前条路径使用虫洞,后面的不使用虫洞的时间来更新答案,即 ans=min(ans,max(len1−w,leni+1)) a n s = m i n ( a n s , m a x ( l e n 1 − w , l e n i + 1 ) ) 。而 w w 为前条路径都共用的边的权值的最大值。我们可以用线段树维护区间边出现的次数最大值,当一条边出现次数等于 i i 时,维护他的权值最大值。这个可以使用链剖解决。因为单调减,所以 len1−w l e n 1 − w 单调加,所以当 len1−w>=ans l e n 1 − w >= a n s 即可退掉。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
const int maxn=3e5+7;
using namespace std;
struct node{
int data,sum;
int lazy;
}t[maxn*4];
struct edge{
int y,w,next;
}g[maxn*2];
int n,m,x,y,w,cnt;
int f[maxn][20],dep[maxn],dfn[maxn],top[maxn],dis[maxn],size[maxn],ls[maxn],val[maxn],b[maxn];
struct rec{
int u,v,l;
}a[maxn];
bool cmp(rec x,rec y)
{
return x.l>y.l;
}
void add(int x,int y,int w)
{
g[++cnt]=(edge){y,w,ls[x]};
ls[x]=cnt;
}
void dfs1(int x,int fa)
{
size[x]=1;
f[x][0]=fa;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (y==fa) continue;
dis[y]=dis[x]+g[i].w;
dep[y]=dep[x]+1;
val[y]=g[i].w;
dfs1(y,x);
size[y]+=size[x];
}
}
void dfs2(int x,int d)
{
top[x]=d;
dfn[x]=++cnt;
int c=0;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (f[x][0]==y) continue;
if (size[y]>size[c]) c=y;
}
if (!c) return;
dfs2(c,d);
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if ((f[x][0]==y) || (y==c)) continue;
dfs2(y,y);
}
}
int lca(int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
int d=dep[y]-dep[x],k=19,t=1<<k;
while (d)
{
if (d>=t) y=f[y][k],d-=t;
t/=2; k--;
}
if (x==y) return x;
k=19;
while (k>=0)
{
if (f[x][k]!=f[y][k])
{
x=f[x][k];
y=f[y][k];
}
k--;
}
return f[x][0];
}
void build(int p,int l,int r)
{
if (l==r)
{
t[p].data=b[l];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].data=max(t[p*2].data,t[p*2+1].data);
}
void ins(int p,int l,int r,int x,int y,int k)
{
if ((l==x) && (r==y))
{
t[p].sum+=1;
t[p].lazy+=1;
return;
}
int mid=(l+r)/2;
if (t[p].lazy)
{
t[p*2].lazy+=t[p].lazy;
t[p*2+1].lazy+=t[p].lazy;
t[p*2].sum+=t[p].lazy;
t[p*2+1].sum+=t[p].lazy;
t[p].lazy=0;
}
if (y<=mid) ins(p*2,l,mid,x,y,k);
else if (x>mid) ins(p*2+1,mid+1,r,x,y,k);
else
{
ins(p*2,l,mid,x,mid,k);
ins(p*2+1,mid+1,r,mid+1,y,k);
}
t[p].sum=max(t[p*2].sum,t[p*2+1].sum);
t[p].data=0;
if (t[p*2].sum==k) t[p].data=max(t[p].data,t[p*2].data);
if (t[p*2+1].sum==k) t[p].data=max(t[p].data,t[p*2+1].data);
}
void change(int x,int y,int k)
{
while (top[x]!=top[y])
{
if (dep[top[x]]>dep[top[y]]) swap(x,y);
ins(1,1,n,dfn[top[y]],dfn[y],k);
y=f[top[y]][0];
}
if (dep[x]>dep[y]) swap(x,y);
if (x!=y) ins(1,1,n,dfn[x]+1,dfn[y],k);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
dfs1(1,0);
cnt=0;
dfs2(1,0);
for (int j=1;j<20;j++)
{
for (int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
}
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
a[i].l=dis[x]+dis[y]-2*dis[lca(x,y)];
a[i].u=x;
a[i].v=y;
}
sort(a+1,a+m+1,cmp);
for (int i=1;i<=n;i++) b[dfn[i]]=val[i];
build(1,1,n);
int ans=a[1].l;
for (int i=1;i<=m;i++)
{
change(a[i].u,a[i].v,i);
int d=t[1].data;
if (a[1].l-d>=ans) break;
ans=min(ans,max(a[1].l-d,a[i+1].l));
}
printf("%d\n",ans);
}