花花的森林
来源:互联网 发布: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.
- 花花的森林
- 花花的森林
- 花花的森林forest
- 【NOIP2017提高A组模拟8.16】花花的森林
- 随机森林对鸢尾花数据的两特征组合的分类结果
- 【jzoj5286】【NOIP2017提高A组模拟8.16】【花花的森林 】【时间倒流】
- JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林
- JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)
- 软件技术的森林时代
- 挪威的森林 - 伍佰
- 危险的森林里
- 森林的故事
- 《挪威的森林》
- 森林的遍历
- 随机森林的优缺点
- 《挪威的森林》完感
- 蚂蚁森林的新发现
- 《挪威的森林》读
- php随机数不断增大
- 网站长期没排名?200指数关键词的SEO诊断视频
- mysql 远程连接
- 第十一周4
- ubuntu14.04或16.04 vpn创建
- 花花的森林
- 自定义TextView解决文字排列不齐和自定义超链接
- php常用正则表达式的整理汇总
- leetcode-2-Add Two Numbers
- 获取当前app的名称和版本号
- Android Service完全解析,关于服务你所需知道的一切
- android 简易3d菜单(伪3d)
- 特殊字符
- 集合中的操作符号