Problem Specification Value
Time Limit 10 Sec
Memory Limit 162 MB
Submit 2130
Solved 613

Description

小 Q 在电子工艺实习课上学习焊接电路板. 一块电路板由若干个元件组成, 我们不妨称之为节点, 并将其用数字 1, 2, 3...... 进行标号. 电路板的各个节点由若干不相交的导线相连接, 且对于电路板的任何两个节点, 都存在且仅存在一条通路 (通路指连接两个元件的导线序列). 在电路板上存在一个特殊的元件称为 “激发器”. 当激发器工作后, 产生一个激励电流, 通过导线传向每一个它所连接的节点. 而中间节点接收到激励电流后, 得到信息, 并将该激励电流传向与它连接并且尚未接收到激励电流的节点. 最终, 激烈电流将到达一些 “终止节点”--接收激励电流之后不再转发的节点. 激励电流在导线上的传播是需要花费时间的, 对于每条边 e, 激励电流通过它需要的时间为 te, 而节点接收到激励电流后的转发可以认为是在瞬间完成的. 现在这块电路板要求每一个 “终止节点” 同时得到激励电路--即保持时态同步. 由于当前的构造并不符合时态同步的要求, 故需要通过改变连接线的构造. 目前小 Q 有一个道具, 使用一次该道具, 可以使得激励电流通过某条连接导线的时间增加一个单位. 请问小 Q 最少使用多少次道具才可使得所有的 “终止节点” 时态同步?

Input

第一行包含一个正整数 N, 表示电路板中节点的个数. 第二行包含一个整数 S, 为该电路板的激发器的编号. 接下来 N-1 行, 每行三个整数 a, b, t. 表示该条导线连接节点 a 与节点 b, 且激励电流通过这条导线需要 t 个单位时间

Output

仅包含一个整数 V, 为小 Q 最少使用的道具次数

Sample Input

3
1
1 2 1
1 3 3

Sample Output

2

HINT

N ≤ 500000, te ≤ 1000000

Source


巨水树形 DP, 局部子树具有贪心决策单调性, 可以贪心子树的权值.

然后就没有什么可说的了...... 看一下代码, 里面的注释还有一些内容.



#include <iostream>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef long long ll;
const int maxn = 500100;

int n, S;
ll  res = 0;

class Graph
{
public:
    struct edge { int u, v, len; edge *next; };
    edge *edges[maxn], epool[2 * maxn];
    int cnt, root;
    int par[maxn];
    ll  dp[maxn];
    void addedge(int u, int v, int len)
    {
        edge *p = &epool[cnt++], *q = &epool[cnt++];
        p->u = u; p->v = v; p->len = len;
            p->next = edges[u]; edges[u] = p;
        q->u = v; q->v = u; q->len = len;
            q->next = edges[v]; edges[v] = q;
        return ;
    }
    void dfs(int p)
    {
        dp[p] = 0;
        for (edge *ep = edges[p]; ep; ep = ep->next)
            if (ep->v != par[p]) {
                par[ep->v] = p;
                dfs(ep->v);
                dp[p] = max(dp[p], dp[ep->v] + ep->len);
            }
        return ;
    }
    void prepare_graph(int _root)
    {
        root = _root;
        par[root] = 0;
        dfs(root);
        return ;
    }
    void work_dp(int p)
    {
        for (edge *ep = edges[p]; ep; ep = ep->next)
            if (par[p] != ep->v) {
                res += dp[p] - (dp[ep->v] + ep->len);
                work_dp(ep->v);
            }
        return ;
    }
} graph;

int main(int argc, char** argv)
{
    scanf("%d%d", &n, &S);
    for (int i = 1, a, b, c; i < n; i++) {
        scanf("%d%d%d", &a, &b, &c);
        graph.addedge(a, b, c);
    }
    graph.prepare_graph(S);
    // Done preparing, now we have a theorem:
    //     It is best to do the work on a parent instead of children.
    //     For the children it must cost much more than parents...
    //     Therefore the theorem is proven.
    graph.work_dp(S);
    printf("%lld\n", res);
    return 0;
}

from pydatagen import *
from math import *
n = randrange(100000, 500000)
s = randrange(1, n + 1)
g = Tree(n, maxchildren=int(sqrt(n)), weighed=True, weight_range=range(1, 1000000))
printf('%d %d\n' % (n, s))
print_oi(g)