刚刚做了二叉苹果树过来的,然后把这题秒了。感觉比二叉苹果树简单很多。
二叉苹果树题解:https://blog.nowcoder.net/n/c8a9812aa008472b8b31391e7995e29c

跟二叉苹果树同样的思路,把边权下放到点权,这里不再赘述,跑一遍树的构造,再进行dfs记忆化dp。
边界是叶子结点,dp[叶子]=val[叶子]
其他结点,要么把儿子割掉,要么让儿子这颗子树已经割掉了叶子。
dp[root]=图片说明 min(val[son],dp[son])

本题注意事项:
1.N为1e5,所以不能用邻接矩阵,最好用链式前向星同时存边的起点终点和边权
2.题目说了long long范围内,按理说不开long long要见祖宗,不过我int也AC了
3.用重要点s作为根跑下树的构造,因为你最后要用dp[s]作为答案的

以下是代码:

//下放边权变为点权,对于每一个子树,要么加上儿子的点权,要么加上儿子为结点的整个子树的dp值

#include <bits/stdc++.h>
using namespace std;
int n,m,s;
const int N=100100;
struct Edge
{
    int v,w,next;
}e[N<<1];
int cnt=0;
int head[N];
int val[N];
int dp[N];
bool haveson[N];
void add(int u,int v,int w)
{
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void pushdown(int root,int pre)
{
    for(int i=head[root];i;i=e[i].next)
    {
        int to=e[i].v;
        if(to==pre) continue;
        haveson[root]=true;
        pushdown(to,root);
        val[to]=e[i].w;
    }
}
void dfs(int root,int pre)
{
    if(!haveson[root]) dp[root]=val[root];
    for(int i=head[root];i;i=e[i].next)
    {
        int to=e[i].v;
        if(to==pre) continue;
        dfs(to,root);
        dp[root]+=min(dp[to],val[to]);
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    while(m--)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    pushdown(s,0);
    dfs(s,0);
    printf("%d\n",dp[s]);
}