[Explanations] tree dp example 5

Questions face Description:

Given a tree of n nodes, where each point to find another node and the distance.


Input Format

A first row of n-integer; next row n-1 is the number of three x, y, z, x to y represents the length of an edge with a z; the data is given to ensure a tree.


Output Format

n rows, a row number, row number indicates the i-th point i and the distance to other points.


Sample data

input
3
1 2 3
1 3 5

output
8
11
13


analysis:

Let's consider only a point distance and how to do it

Obviously, traversing the entire map again dfs cumulative distance and can be.

void dp(int x,LL last){
    vis[x]=1;//当前点是否遍历过
    num[x]=1;//以他为根的点的个数
    sum+=last;//last是根节点到当前点的距离,因为距离和并不是每条边只经过一次,边是要重复累加的,所以我们在累加last的时候直接类加上权值
    for (int i=linkk[x];i;i=e[i].Next){
	    int y=e[i].y;
	    LL v=e[i].v;
	    if (vis[y]) continue;
	    dp(y,last+e[i].v);//继续遍历
	    num[x]+=num[y];//累加上点的个数
	}
}

After considering the practice a point we would like to practice more points again

In fact, for to a certain point, its distance and the only other point to it and about the father's weight.
For the other side, the number and frequency of it is taking away its father is the same.
But even number between it and the father's side will go through changes.
For example, in FIG. (Assuming 1 right side)
Here Insert Picture Descriptionwe first calculate the size of each point in the subtree.
There Bottom:
Here Insert Picture Description
Suppose we now claim 2 as the root of the distance to another point.
2 is a father of
the other side through the same number of times, but the number of edges through changes 1-> 2
father 1 to point 4, 5, the number of passes sides 1-> 2 is 2.
However, the 2 4,5 but not through the side 1-> 2.
Therefore, with two root distance and distance ratio and a root side of the two small 1-> 2,
2, 4, 7 the number of passes to the side of the 1-> 2 to 3
, but 1 to 3,4 , 7 but do not go through this edge.
Therefore, with two root ratio and a distance from a root edge and a plurality of three 1-> 2 is
generally more than one edge 1-> 2.

We found that:
For a point y, his father is x, the right side is E [i] .v
E [i] .v and more times after that:
( n n in m [ Y ] 1 ) ( n in m [ Y ] 1 ) (N-num [and] -1) - (num [and] -1)
n n in m [ Y ] 1 n-num [and] -1 is the number of points in addition to the current sub-tree, and his father's point, because these points have to go through this edge, so much the number of these.

n in m [ Y ] 1 num [and] -1 is the number of its sub-tree, when its father to her child tree is the result of this edge, but it is not going to go through, so you need to lose.

After finishing becomes:
n 2 n in m [ Y ] n-2 * num [and]

Suppose DP [i] where i is represented by the root node and the distance to the other.
We push the following formula:
d p [ Y ] = d p [ x ] + ( n 2 n in m [ Y ] ) e [ i ] . v   ( y s o n ( x ) ) dp[y]=dp[x]+(n-2*num[y])*e[i].v\ (y\in son(x))


Code


#include<bits/stdc++.h>
using namespace std;
#define LL long long
struct node{
    int y,Next;
	LL v;
}e[1000010];
int linkk[1000010];
int fa[1000010];
int num[1000010];
LL fav[1000010];
LL Dp[1000010];
bool vis[1000010];
LL sum=0;
int n;
int len=0;
void insert(int x,int y,LL v){
    e[++len].Next=linkk[x];
    linkk[x]=len;
    e[len].y=y;
    e[len].v=v;
}
void dp(int x,LL last){
    vis[x]=1;
    num[x]=1;
    sum+=last;
    for (int i=linkk[x];i;i=e[i].Next){
	    int y=e[i].y;
	    LL v=e[i].v;
	    if (vis[y]) continue;
	    fa[y]=x;
	    fav[y]=e[i].v;
	    dp(y,last+e[i].v);
	    num[x]+=num[y];
	}
}//第一个预处理
void treedp(int x){
    vis[x]=1;
    for (int i=linkk[x];i;i=e[i].Next){
	    int y=e[i].y;
	    if (vis[y]) continue;
	    Dp[y]=Dp[x]+(n-num[y])*e[i].v-(num[y])*e[i].v;//之前那个公式
	    treedp(y);
	}
}
int main(){
	freopen("t5.in","r",stdin);
	freopen("t5.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<n;i++){
	    int x,y;
	    LL v;
	    scanf("%d %d %lld",&x,&y,&v);
	    insert(x,y,v);
	    insert(y,x,v);
	}
	fa[1]=0;
	dp(1,0);
	printf("%lld",sum);
	Dp[1]=sum;//假设1是根,那么1就是sum值
	memset(vis,0,sizeof(vis));
	treedp(1);
	for (int i=2;i<=n;i++) printf("\n%lld",Dp[i]);
	return 0;
}

Guess you like

Origin blog.csdn.net/huang_ke_hai/article/details/88534703