题目描述 花花有一棵带n 个顶点的树T,每个节点有一个点权ai。 有一天,他认为拥有两棵树更好一些。所以,他从T 中删去了一条边。
第二天,他认为三棵树或许又更好一些。因此,他又从他拥有的某一棵树中去除了一条边。
如此往复。每一天,花花都会删去一条尚未被删去的边,直到他得到了一个包含了n 棵只有一个点的树的森林。
定义一条简单路径1的权值为路径上点权之和,一棵树的直径为树上权值最大的简单路径。
花花认为树最重要的特征就是它的直径。所以他想请你算出任一时刻他拥有的所有树的直径的乘积。因为这个数可能很大,他要求你输出乘积对10^9 +
7 取模之后的结果。 输入 输入的第一行包含一个整数n,表示树T 上顶点的数量。 下一行包含n 个空格分隔的整数ai,表示顶点的权值。
之后的n-1 行中,每一行包含两个用空格分隔的整数xi 和yi,表示节点xi 和yi 之间连有一条边,编号为i。 再之后n-1
行中,每一行包含一个整数kj,表示在第j 天里会被删除的边的编号 输出 输出n 行。 在第i 行,输出删除i-1
条边之后,所有树直径的乘积对10^9 + 7 取模的结果。
样例输入
3
1 2 3
1 2
1 3
2
1
样例输出
6
9
6提示
初始,树的直径为6(由节点2、1 和3 构成的路径)。在第一天之后,得到了两棵直径都为3的树。第二天之后,得到了三棵直径分别为1,2,3 的树,乘积为6。 顶点不重复出现的路径
• 对于40% 的数据:N <= 100;
•另有20% 的数据:N <= 1000;
• 另有20% 的数据:N <= 10^4;
• 对于100% 的数据:N <= 10^5; ai<= 10^4。
倒着加边,并查集维护。有一个结论两颗子树合并,其直径端点一定在原直径端点上。由于原图是树,所以我们可以采用倍增LCA来求解两点间的距离。
const p=1000000007;
var
tot,i,n,m,x1,x2,y1,y2,x,y,d,root1,root2,max,z:longint;
ret,next,head,fa,deep,w,q,u,v:array[0..200022] of longint;
ans,l:array[0..200022] of int64;
f,dis,s:array[0..200000,0..20] of int64;
procedure ins(u,v:longint);
begin
tot:=tot+1;
ret[tot]:=v;
next[tot]:=head[u];
head[u]:=tot;
end;
function gpow(x,k:longint):int64;
var
t:int64;
begin
if k=1 then exit(x);
t:=gpow(x,k div 2);
t:=t*t mod p;
if k mod 2=1 then t:=t*x mod p;
exit(t);
end;
function find(i:longint):longint;
begin
if fa[i]<>i then fa[i]:=find(fa[i]);
exit(fa[i]);
end;
procedure dfs(u,pre:longint);
var
i,v:longint;
begin
i:=head[u];
while i<>0 do
begin
v:=ret[i];
if v<>pre then
begin
deep[v]:=deep[u]+1;
f[v,0]:=u;
dis[v,0]:=w[v]+w[u];
dfs(v,u);
end;
i:=next[i];
end;
end;
procedure init;
var
i,j:longint;
begin
j:=1;
while (1<<j)<=n do
begin
for i:=1 to n do
if f[i,j-1]<>-1 then
begin
f[i,j]:=f[f[i,j-1],j-1];
dis[i,j]:=dis[i,j-1]+dis[f[i,j-1],j-1]-w[f[i,j-1]];
end;
j:=j+1;
end;
end;
function lca(a,b:longint):longint;
var
i,j,t:longint;
begin
d:=w[a]+w[b];
if deep[a]<deep[b] then begin t:=a;a:=b;b:=t; end;
i:=0;
while (1<<i)<=deep[a] do
i:=i+1;
i:=i-1;
for j:=i downto 0 do
if (deep[a]-1<<j)>=deep[b] then
begin
d:=d+dis[a,j]-w[a];
a:=f[a,j];
end;
if a=b then begin d:=d-w[a]; exit(a); end;
for j:=i downto 0 do
if (f[a,j]<>-1)and(f[a,j]<>f[b,j]) then
begin
d:=d+dis[a,j]-w[a];
d:=d+dis[b,j]-w[b];
a:=f[a,j];
b:=f[b,j];
end;
d:=d+w[f[a,0]];
exit(f[a,0]);
end;
begin
readln(n);
ans[n]:=1;
for i:=1 to n do
begin
read(w[i]);
ans[n]:=ans[n]*w[i] mod p;
end;
readln;
for i:=1 to n-1 do
begin
readln(u[i],v[i]);
ins(u[i],v[i]);
ins(v[i],u[i]);
end;
for i:=1 to n-1 do
readln(q[i]);
deep[1]:=1;
dis[1,0]:=w[1];
dfs(1,-1);
f[1,0]:=-1;
init;
for i:=1 to n do
begin
fa[i]:=i;
s[i,1]:=i;
s[i,2]:=i;
l[i]:=w[i];
end;
for i:=n-1 downto 1 do
begin
root1:=find(u[q[i]]);
root2:=find(v[q[i]]);
x1:=s[root1,1];
x2:=s[root1,2];
y1:=s[root2,1];
y2:=s[root2,2];
if l[root1]>l[root2] then
begin
max:=l[root1];
x:=x1;
y:=x2;
end
else
begin
max:=l[root2];
x:=y1;
y:=y2;
end;
z:=lca(x1,y1);
if d>max then
begin
max:=d;
x:=x1;
y:=y1;
end;
z:=lca(x1,y2);
if d>max then
begin
max:=d;
x:=x1;
y:=y2;
end;
z:=lca(x2,y1);
if d>max then
begin
max:=d;
x:=x2;
y:=y1;
end;
z:=lca(x2,y2);
if d>max then
begin
max:=d;
x:=x2;
y:=y2;
end;
ans[i]:=ans[i+1]*gpow(l[root1]*l[root2] mod p,p-2) mod p*max mod p;
fa[root1]:=root2;
l[root2]:=max;
s[root2,1]:=x;
s[root2,2]:=y;
end;
for i:=1 to n do
writeln(ans[i]);
end.