统计损失

统计损失
题目描述
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;
}




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值