宠物之战 解题报告

题意简而言之就是:求每一个点作根时,叶子节点的深度之和。
这么一看就发现,这是很经典的换根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;
}

浙公网安备 33010602011771号