宠物之战 解题报告

题目描述
题意简而言之就是:求每一个点作根时,叶子节点的深度之和。
这么一看就发现,这是很经典的换根dp。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define add(u,v,w) adds(u,v,w),adds(v,u,w)
using namespace std;
typedef long long ll;
inline int read(){
  register int x=0;
  char c=getchar();
  while(c<'0' || '9'<c) c=getchar();
  while('0'<=c && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
  return x;
}
const int N=1e5+1000;
int n,q,m,cnt,rt;
struct Edge{int from,to,dis;}e[N<<1];
int num,h[N];
void adds(int f,int t,int d){e[++num].from=h[f],e[num].to=t,e[num].dis=d,h[f]=num;}
int f[N];
ll ans,val,dep;
int dfs0(int u,int fa){
  bool flag=true;
  for(int i=h[u],v;i;i=e[i].from){
    v=e[i].to;
    if(v==fa) continue;
    flag=false;
    dep+=e[i].dis;
    f[u]+=dfs0(v,u);
    dep-=e[i].dis;
  }
  if(flag){val+=dep,cnt++,f[u]=1;}
  return f[u];
}
void dfs1(int u,int fa){
  ans+=val;
  //printf("%d %d\n",u,val);
  for(int i=h[u],v;i;i=e[i].from){
    v=e[i].to;
    if(v==fa) continue;
    val+=1ll*e[i].dis*(cnt-2*f[v]);
    dfs1(v,u);
    val-=1ll*e[i].dis*(cnt-2*f[v]);
  }
}
int main(){
  freopen("senso.in","r",stdin);
  freopen("senso.out","w",stdout);
  n=read(),m=read();
  for(int i=1,u,v,w;i<=m;i++) w=read(),v=read(),u=read(),add(u,v,w);
  dfs0(1,0);
  //putchar('\n');
  dfs1(1,0);
  printf("%lld",ans);
  return 0;
}


posted @ 2025-07-07 16:39  XiaoZi_qwq  阅读(4)  评论(0)    收藏  举报