花花的森林

来源:互联网 发布:spss多组数据t检验 编辑:程序博客网 时间:2024/04/28 11:47

题目描述 花花有一棵带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;vartot,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;vart: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);vari,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;vari,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;vari,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.
0 0
原创粉丝点击