Road Projects CodeForces - 1016F (树形dp)

There are nn cities in the country of Berland. Some of them are connected by bidirectional roads in such a way that there exists exactly one path, which visits each road no more than once, between every pair of cities. Each road has its own length. Cities are numbered from 11 to nn.

The travelling time between some cities vv and uu is the total length of the roads on the shortest path from vv to uu.

The two most important cities in Berland are cities 11 and nn.

The Berland Ministry of Transport decided to build a single new road to decrease the traffic between the most important cities. However, lots of people are used to the current travelling time between the most important cities, so the new road shouldn't change it too much.

The new road can only be built between such cities vv and uu that v≠uv≠u and vv and uuaren't already connected by some road.

They came up with mm possible projects. Each project is just the length xx of the new road.

Polycarp works as a head analyst at the Berland Ministry of Transport and it's his job to deal with all those mm projects. For the ii-th project he is required to choose some cities vv and uu to build the new road of length xixi between such that the travelling time between the most important cities is maximal possible.

Unfortunately, Polycarp is not a programmer and no analyst in the world is capable to process all projects using only pen and paper.

Thus, he asks you to help him to calculate the maximal possible travelling time between the most important cities for each project. Note that the choice of vv and uucan differ for different projects.

Input

The first line contains two integers nn and mm (3≤n≤3⋅1053≤n≤3⋅105, 1≤m≤3⋅1051≤m≤3⋅105) — the number of cities and the number of projects, respectively.

Each of the next n−1n−1 lines contains three integers vivi, uiui and wiwi (1≤vi,ui≤n1≤vi,ui≤n, 1≤wi≤1091≤wi≤109) — the description of the ii-th road. It is guaranteed that there exists exactly one path, which visits each road no more than once, between every pair of cities.

Each of the next mm lines contains a single integer xjxj (1≤xj≤1091≤xj≤109) — the length of the road for the jj-th project.

Output

Print mm lines, the jj-th line should contain a single integer — the maximal possible travelling time between the most important cities for the jj-th project.

Example

Input

7 2
1 2 18
2 3 22
3 4 24
4 7 24
2 6 4
3 5 12
1
100

Output

83
88

思路:先考虑加入一条权重为0的边,看加入这条边使得1到n的最短路径缩短了多少。我们要先求出使得最短路缩短最少的两个点即可,最后查询就是 short - 最短缩短 + x

下面考虑如何用dfs求出最少的缩短距离,首先考虑一种不缩短的方式(也就是加入一条边使得路径增长了),考虑,只要出现这样的情况:当存在一个点,它不在最短路径里面,并且它有一个以上子节点,那么只要连接它的一个子节点到n,这样做必然使得路径增长,所以最后答案必然是short.

其次:考虑选择的点是否属于最短路径上,先dfs一遍记录从1到i的距离d[i],然后分点在不在最短路径上即可计算出最短的缩短距离。

代码:

//cf 1016F
#include <bits/stdc++.h>
const int maxn=3e5+7;
#define mod 998244353
#define Lson l,m,rt<<1
#define Rson m+1,r,rt<<1|1
const long long inf=(long long)1e18;
typedef long long ll;
using namespace std;
int n,m;
vector<pair<int,int> > g[maxn];
ll d[maxn];
int siz[maxn],f[maxn];
int L[maxn],R[maxn];
ll dif,mn;
int T;
void precal(int u,int pre)
{
    f[u]=pre;
    L[u]=T++;
    siz[u]=1;
    for(auto &t: g[u])
    {
        int v=t.first,w=t.second;
        if(v==pre) continue;
        d[v]=d[u]+w;
        precal(v,u);
        siz[u]+=siz[v];
    }
    R[u]=T++;
}
inline int isp(int v,int u)
{
    return L[v]<=L[u]&&R[v]>=R[u];
}
void dfs(int u,int pre)
{
    dif=min(dif,max(0ll,-(mn-d[u])));
    if(pre!=0&&f[pre]!=0)
    {
        dif=min(dif,max(0ll,-(d[f[pre]]-d[u])));//当两个点都在最短路径上,直接减就行
    }
    for(auto &t: g[u])
    {
        int v=t.first,w=t.second;
        if(v==pre) continue;
        if(isp(v,n)==0)
        {
            dif=min(dif,max(0ll,-(mn+w-d[u])));//一个点在,另一个不在
            mn=max(mn,w+d[u]);
            if(pre!=0)
            {
                dif = min(dif, max(0ll, -(w - d[u] + d[pre])));//连接v和u的父亲
            }
        }
    }
    for(auto &t :g[u])
    {
        int v=t.first,w=t.second;
        if(v==pre) continue;
        if(isp(v,n))
        {
            dfs(v,u);
        }
    }
}
int main(int argc, char const *argv[])
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1,u,v,w;i<n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        g[u].push_back(make_pair(v,w));
        g[v].push_back(make_pair(u,w));
    }
    T=0;
    precal(1,0);
    ll cur=d[n];
    dif=inf,mn=-inf;
    for(int i=1;i<=n;i++)
    {
        if(isp(i,n)==0&&siz[i]>1)//可以不减少最小距离
        {
            dif=0;
        }
    }
    if(dif>0) dfs(1,0);
    for(int i=1,x;i<=m;i++)
    {
        scanf("%d",&x);
        printf("%lld\n",min(cur,cur-dif+1ll*x));
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值