JZOJ 3844. 统计损失(count)

 题目

Description

SJY有一天被LLT紧急召去计算一些可能的损失。LLT元首管理的SHB国的交通形成了一棵树,现在将会出现一颗陨石砸在SHB国中,并且陨石砸毁的必定是SHB国构成的交通树上的一条路径。SHB国的损失可表示为被砸毁的路径上的所有城市价值之积。现在还暂时无法确定陨石的掉落路线,所以LLT元首希望SJY能够告诉他SHB国在受到每一种砸毁方式后会受到的损失之和模10086之后的值。注意:单独一个节点也被认为是合法的路径。
 

Input

第1行一个数n,表示城市数。
第2行n个数,第i个数表示第i个城市的价值。
第3到n+1行,每行两个数u,v,表示城市u,v之间有一条道路。

Output

包含一个数,表示SHB国将受到的损失之和。
 

Sample Input

5
7 6 6 1 1 
1 2
2 3
2 4
1 5

Sample Output

778
 

Data Constraint

对于20%的数据,n<=100;
对于50%的数据,n<=3000;
对于100%的数据,n<=100000。

 

分析

 

  • 树形DP
  • 设f[x]为他的子树的所有路径乘积的和
  • 那么显然f[x]=f[v]*a[x]
  • 然后统计答案的话
  • 我们还需要加上一个他的每个子节点两两相乘*a[i]
  • 因为子树也存在路径
  • 再加本身节点值f[x],a[x];

代码

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #define ll long long
 7 const int mod=10086;
 8 using namespace std;
 9 struct sb
10 {
11     int to,nx;
12 }g[400001];
13 int list[400001],cnt;
14 void add(int x,int y)
15 {
16     g[++cnt].to=y; g[cnt].nx=list[x]; list[x]=cnt;
17     g[++cnt].to=x; g[cnt].nx=list[y]; list[y]=cnt;
18 }
19 ll f[100001],a[100001],h[100001];
20 ll ans;
21 void dfs(int x,int fa)
22 {
23     f[x]=a[x];
24     for (int i=list[x];i;i=g[i].nx)
25     {
26         int y=g[i].to;
27         if (y==fa) continue;
28         dfs(y,x);
29         f[x]=(f[x]+(a[x]*f[y])%mod)%mod;
30         ans=(ans+f[y]*(a[x]*h[x])%mod)%mod;
31         h[x]=(h[x]+f[y])%mod;
32     }
33     ans=(ans+f[x])%mod;
34 }
35 int main()
36 {
37     int n;
38     scanf("%d",&n);
39     for (int i=1;i<=n;i++)
40       scanf("%d",&a[i]);
41     for (int i=1,x,y;i<=n-1;i++)
42     {
43         scanf("%d%d",&x,&y);
44         add(x,y);
45     }
46     dfs(1,-1);
47     cout<<ans;
48     return 0;
49 }
原文地址:https://www.cnblogs.com/zjzjzj/p/11805835.html