CodeForces-1004E Sonya and Ice Cream(树型DP+RMQ)

E. Sonya and Ice Cream

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Sonya likes ice cream very much. She eats it even during programming competitions. That is why the girl decided that she wants to open her own ice cream shops.

Sonya lives in a city with nn junctions and n−1n−1 streets between them. All streets are two-way and connect two junctions. It is possible to travel from any junction to any other using one or more streets. City Hall allows opening shops only on junctions. The girl cannot open shops in the middle of streets.

Sonya has exactly kk friends whom she can trust. If she opens a shop, one of her friends has to work there and not to allow anybody to eat an ice cream not paying for it. Since Sonya does not want to skip an important competition, she will not work in shops personally.

Sonya wants all her ice cream shops to form a simple path of the length rr (1≤r≤k1≤r≤k), i.e. to be located in different junctions f1,f2,…,frf1,f2,…,fr and there is street between fifi and fi+1fi+1 for each ii from 11 to r−1r−1.

The girl takes care of potential buyers, so she also wants to minimize the maximum distance between the junctions to the nearest ice cream shop. The distance between two junctions aa and bb is equal to the sum of all the street lengths that you need to pass to get from the junction aa to the junction bb. So Sonya wants to minimize

maxamin1≤i≤rda,fimaxamin1≤i≤rda,fi

where aa takes a value of all possible nn junctions, fifi — the junction where the ii-th Sonya's shop is located, and dx,ydx,y — the distance between the junctions xx and yy.

Sonya is not sure that she can find the optimal shops locations, that is why she is asking you to help her to open not more than kk shops that will form a simple path and the maximum distance between any junction and the nearest shop would be minimal.

Input

The first line contains two integers nn and kk (1≤k≤n≤1051≤k≤n≤105) — the number of junctions and friends respectively.

Each of the next n−1n−1 lines contains three integers uiui, vivi, and didi (1≤ui,vi≤n1≤ui,vi≤n, vi≠uivi≠ui, 1≤d≤1041≤d≤104) — junctions that are connected by a street and the length of this street. It is guaranteed that each pair of junctions is connected by at most one street. It is guaranteed that you can get from any junctions to any other.

Output

Print one number — the minimal possible maximum distance that you need to pass to get from any junction to the nearest ice cream shop. Sonya's shops must form a simple path and the number of shops must be at most kk.

Examples

input

Copy

6 2
1 2 3
2 3 4
4 5 2
4 6 3
2 4 6

output

Copy

4

input

Copy

10 3
1 2 5
5 7 2
3 2 6
10 6 3
3 8 1
6 4 2
4 1 6
6 9 4
5 2 5

output

Copy

7

Note

In the first example, you can choose the path 2-4, so the answer will be 4.

The first example.

In the second example, you can choose the path 4-1-2, so the answer will be 7.

The second example.

题意:要求在树上找一条长为k的链,使得其它点到这条链的距离的最大值尽量小

题解:又是一个树的直径问题,当链在直径上一定是最优的。问题就变成在直径上选一段长为k的链,可以将这条链从一端移动到另一端,并维护最优解。

需要记录3个信息:以链的左端点为根的子树到左端点的距离DL,以链的又断电为根的子树到右端点的距离DR,除端点外以链上的点为根的子树到链的距离DM(当然子树不能包含其它链上的点)

答案就是ans = min(ans,max(DL,DR,max(DM[u])))

DM很容易得到,直接从直径上的每个点出发DFS一遍即可,然后每次移动时RMQ查询一下。

设链是从左往右移动的,left和right分别为直径的左端点和右端点,u和v分别是链的左端点和右端点

DL = max(DL + dis(u,u+1),DM[u+1])

DM=dis(left,right)-dis(left,v)

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define add(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
#define sub(x,y) x=((x)-(y)<0)?(x)-(y)+mod:(x)-(y)
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e5 + 5;

struct Edge {
    int v, w, nxt;
} E[MX << 1];
int head[MX], tot, n, k;
VI ver;
void init() {
    memset(head, -1, sizeof(head));
    tot = 0;
}
void edge_add(int u, int v, int w) {
    E[tot] = (Edge) {v, w, head[u]}, head[u] = tot++;
}
int d1[MX], d2[MX], d3[MX], d4[MX], mark[MX];
void dfs(int u, int pre, int dis, int d[]) {
    d[u] = dis;
    for(int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == pre) continue;
        dfs(v, u, dis + E[i].w, d);
    }
}
bool DFS(int u, int pre, int g) {
    if(u == g) {ver.push_back(u); return 1;}
    for(int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == pre) continue;
        if(DFS(v, u, g)) {
            mark[u] = 1;
            ver.push_back(u);
            return 1;
        }
    }
    return 0;
}
void solve(int u, int pre, int dis, int rt) {
    d3[rt] = max(d3[rt], dis);
    for(int i = head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == pre || mark[v]) continue;
        solve(v, u, dis + E[i].w, rt);
    }
}
int dp[MX][30];
void ST(int n) {
    for (int i = 0; i < n; i++) dp[i][0] = d3[ver[i]];
    for (int j = 1; (1 << j) <= n; j++) {
        for (int i = 0; i + (1 << j) - 1 < n; i++) {
            int a = dp[i][j - 1] , b = dp[i + (1 << (j - 1))][j - 1];
            dp[i][j] = max(a, b);
        }
    }
}
int RMQ(int l, int r) {
    int k = 0;
    while ((1 << (k + 1)) <= r - l + 1) k++;
    int a = dp[l][k], b = dp[r - (1 << k) + 1][k];
    return max(a, b);
}

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local
    cin >> n >> k;
    init();
    rep(i, 1, n) {
        int u, v, d;
        scanf("%d%d%d", &u, &v, &d);
        edge_add(u, v, d);
        edge_add(v, u, d);
    }
    dfs(1, 1, 0, d1);
    int u = 0; rep(i, 1, n + 1) if(d1[i] > d1[u]) u = i;
    dfs(u, u, 0, d2);
    int v = 0; rep(i, 1, n + 1) if(d2[i] > d2[v]) v = i;
    mark[u] = mark[v] = 1; DFS(u, u, v);
    reverse(ver.begin(), ver.end());
    rep(i, 0, ver.size()) solve(ver[i], ver[i], 0, ver[i]);
    ST(ver.size());
    rep(i, 0, ver.size() - 1) {
        int x = ver[i];
        for(int j = head[x]; ~j; j = E[j].nxt) if(E[j].v == ver[i + 1]) d4[x] = E[j].w;
    }
    k = min(k, (int)ver.size());
    int l = 0, r = d2[v] - d2[ver[k - 1]];
    int ans = INF;
    rep(i, 0, ver.size() - k + 1) {
        int tmp = RMQ(i, i + k - 1);
        ans = min(ans, max(tmp, max(l, r)));
        l = max(l + d4[ver[i]], d3[ver[i]]);
        if(i + k < ver.size()) r = d2[v] - d2[ver[i + k]];
    }
    printf("%d\n", ans);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值