统计损失
题目描述
SJY有一天被LLT紧急召去计算一些可能的损失。LLT元首管理的SHB国的交通形成了一棵树,现在将会出现一颗陨石砸在SHB国中,并且陨石砸毁的必定是SHB国构成的交通树上的一条路径。SHB国的损失可表示为被砸毁的路径上的所有城市价值之积。现在还暂时无法确定陨石的掉落路线,所以LLT元首希望SJY能够告诉他SHB国在受到每一种砸毁方式后会受到的损失之和模10086之后的值。注意:单独一个节点也被认为是合法的路径。
输入
第1行一个数n,表示城市数。
第2行n个数,第i个数表示第i个城市的价值。
第3到n+1行,每行两个数u,v,表示城市u,v之间有一条道路。
输出
包含一个数,表示SHB国将受到的损失之和。
样例输入
5
7 6 6 1 1
1 2
2 3
2 4
1 5
样例输出
778
提示
n<=100;
n<=3000;
题目描述
SJY有一天被LLT紧急召去计算一些可能的损失。LLT元首管理的SHB国的交通形成了一棵树,现在将会出现一颗陨石砸在SHB国中,并且陨石砸毁的必定是SHB国构成的交通树上的一条路径。SHB国的损失可表示为被砸毁的路径上的所有城市价值之积。现在还暂时无法确定陨石的掉落路线,所以LLT元首希望SJY能够告诉他SHB国在受到每一种砸毁方式后会受到的损失之和模10086之后的值。注意:单独一个节点也被认为是合法的路径。
输入
第1行一个数n,表示城市数。
第2行n个数,第i个数表示第i个城市的价值。
第3到n+1行,每行两个数u,v,表示城市u,v之间有一条道路。
输出
包含一个数,表示SHB国将受到的损失之和。
样例输入
5
7 6 6 1 1
1 2
2 3
2 4
1 5
样例输出
778
提示
n<=100;
n<=3000;
n<=100000;
当n<=3000时
可以n^2,遍历每一条边,轻松愉快。
当n<=100000时
树形DP
很明显,只要搜一遍,再把子树两两相乘在加上本身。
两两相乘可以用数学方法计算
#include <algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define maxn 100086
#define Mod 10086;
struct node
{
int next,to;
}edge[maxn*2];
int head[maxn],num,val[maxn],f[maxn],ans;
bool visit[maxn];
void add(int from,int to)
{
edge[++num].next=head[from];
edge[num].to=to;
head[from]=num;
}
void dfs(int now)
{
long long tmp=0,temp=0;
visit[now]=true;
for(int i=head[now];i!=0;i=edge[i].next)
if(!visit[edge[i].to])
{
dfs(edge[i].to);
tmp+=f[edge[i].to];
temp+=f[edge[i].to]*f[edge[i].to];
}
f[now]=((tmp+1)*val[now])%Mod;
tmp=tmp*tmp;
tmp=(tmp-temp)/2;
tmp%=Mod;
tmp=(tmp*val[now])%Mod;
ans=(ans+f[now]+tmp)%Mod;
}
int main()
{
num=0;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
val[i]%=Mod;
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1);
printf("%d\n",ans);
return 0;
}