题目
SJY有一天被LLT紧急召去计算一些可能的损失。LLT元首管理的SHB国的交通形成了一棵树,现在将会出现一颗陨石砸在SHB国中,并且陨石砸毁的必定是SHB国构成的交通树上的一条路径。SHB国的损失可表示为被砸毁的路径上的所有城市价值之积。现在还暂时无法确定陨石的掉落路线,所以LLT元首希望SJY能够告诉他SHB国在受到每一种砸毁方式后会受到的损失之和模10086之后的值。注意:单独一个节点也被认为是合法的路径。
题意
给你一棵树,求树上任意一条路径的节点的积的和。
分析
我们很自然的想到了树形dp,那么怎么dp呢?
我们可以先考虑一下它所说的路径是什么?
明显有两种情况:
1.头尾的lca为它们的其中一个
2.头尾的lca不是它们中的一个(即是一个“V”字形的路径)
考虑完了,我们可以设状态:
我们用
f[i]
表示经过头(或尾)为i的第一种情况的答案和(直线)。
那么:
f[i]=∑f[son[i]]∗v[i](k=son[i])
第二种情况其实并没有那么麻烦,我们发现若两点(x,y)的lca为i
那么可以划分为x到i的直线(第一种情况)*y到i的直线。
且第二种情况是不能传递上fa[i]的(想想为什么)
然后我们便可以直接计算第二种情况,第一种就转移即可。
到此,便很好的解决了这个问题了。
const mo=10086;
var
n,i,x,y,nu:longint;ans:int64;
c,f:array[1..100000] of longint;
b,next,last:array[1..200000] of longint;
procedure insert(x,y:longint);
begin
inc(nu);
b[nu]:=y;
next[nu]:=last[x];
last[x]:=nu;
end;
procedure dfs(x,y:longint);
var p:longint;su:int64;
begin
p:=last[x];su:=0;
while p<>0 do begin
if b[p]<>y then begin
dfs(b[p],x);
f[x]:=(f[x]+f[b[p]]*c[x])mod mo;
ans:=(ans+su*f[b[p]]*c[x])mod mo;
su:=su+f[b[p]];end;
p:=next[p];
end;
ans:=(ans+f[x])mod mo;
end;
begin
readln(n);
for i:=1 to n do begin read(c[i]);f[i]:=c[i];end;
for i:=1 to n-1 do begin
readln(x,y);
insert(x,y);
insert(y,x);
end;
dfs(1,0);
writeln(ans);
end.