Problem D: 一棵树
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 59 Solved: 15
[ Submit][ Status][ Web Board]
Description
给你一颗有n个顶点的树。树上有n-1条边,边上的权值c代表一对顶点(u,v)的距离,定义为x到y上的距离,求
。
Input
第一行一个整数T,代表总共T(T<=10)组数据
第二行一个整数n(n<=100,000),这颗树有n个顶点。
接下来n-1行,每行3个整数,u,v,c,代表u到v之间有一条长度为c(1<=c<=100,000)的边。
Output
每行输出一个整数,输出的值。
Sample Input
141 2 11 3 21 4 3
Sample Output
18
HINT
解题思路:题目的要求是求出任意两点的距离和,,如果仔细思考下就会发现,每条边被经过的次数为这条边两边的节点的数量乘积,这样的话我们只要对每条边都求出它们被经过的次数乘以它们的距离相加即可!遍历节点的话,我们DFS一遍就可以了。
AC代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<time.h>
#include<map>
#include<string>
#include<algorithm>
#include<set>
#define N 100005
using namespace std;
int n, cnt, head[N];
long long num[N]; //注意开long long啊
long long sum;
struct Edge
{
int End;
int Len;
int next;
}e[2 * N];
void Add_Edge(int u, int v, int w)
{
e[cnt].End = v;
e[cnt].Len = w;
e[cnt].next = head[u];
head[u] = cnt ++;
}
void DFS(int st, int fa) //st为某个节点,fa为st的父节点
{
num[st] = 1;
for(int i = head[st]; i != -1; i = e[i].next)
{
int en = e[i].End;
if(en != fa) //我们是从父节点一路向下遍历,不能反向
{
DFS(en, st);
num[st] += num[en]; //num[en]为这条路一边(遍历方向)的节点数
sum += num[en] * (n - num[en]) * e[i].Len;
}
}
}
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
cnt = 0;
sum = 0;
memset(head, -1, sizeof(head));
scanf("%d", &n);
for(int i = 0; i < n - 1; i++)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
Add_Edge(u, v, w);
Add_Edge(v, u, w);
}
DFS(1, -1); //把节点1作为根节点一层一层遍历下去
printf("%lld\n", sum);
}
return 0;
}