树(tree)
题目描述
给定一棵nn个节点的树,树上每个点有点权xixi 。
对于一条路径i1,i2,…,ik,定义路径的权值为xi1×xi2×⋯×xik/k
现在要找一条权值最小的路径,请以分数的形式输出路径的权值。
输入
第一行包括一个整数nn。
第二行到第nn行每行两个整数x,y(1≤x,y≤n)x,y(1≤x,y≤n),表示一条xx到yy的树边。
第n+1n+1行到第2n2n行,依次为x1,x2,…,xnx1,x2,…,xn。
输出
输出答案的分数形式,形如a/ba/b,其中a,ba,b互质且为正整数。
样例输入
6
1 2
1 3
2 6
3 4
3 5
1
1
2
3
1
1
样例输出
1/3
提示
对于100%100%的数据,n≤106,xi≤109n≤106,xi≤109。
测试点编号 |
nn |
其它性质 |
1,2,3,41,2,3,4 |
103103 |
|
5,6,75,6,7 |
106106 |
不存在一个节点的度数超过22 |
8,9,108,9,10 |
106106 |
来源
这题有点诡异。。。
如果整棵树上的最小值大于一,答案就是最小值,因为乘起来除以2肯定不优
那么我们考虑树上最长的1的序列
如果有111121111这样若干1夹一个2的答案,那么它可能是答案。
不然就是最长1的序列。
证明的话,分分类吧。。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 1000005
using namespace std;
int n,head[maxn],f[maxn],g[maxn],up[maxn],w[maxn];
int fl,tot,t1,t2,ans1,ans2;
struct node{
int v,nex;
}e[maxn*2];
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int fa){
int Max=0,max2=0;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa){
dfs(e[i].v,k);
if(f[e[i].v]>Max){
max2=Max;
Max=f[e[i].v];
}
else if(f[e[i].v]>max2)max2=f[e[i].v];
}
}
if(w[k]==1){
f[k]=Max+1;
if(max2>0)g[k]=max2+1;
}
else f[k]=g[k]=0;
}
void dfs2(int k,int fa){
if(w[fa]!=1)up[k]=0;
else {
if(f[fa]==f[k]+1)up[k]=g[fa];
else up[k]=f[fa];
up[k]=max(up[k],up[fa]+1);
}
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa){
dfs2(e[i].v,k);
}
}
}
void work(int k,int fa){
if(w[k]==1){
ans1=max(ans1,max(f[k]+g[k]-1,f[k]+up[k]));
//cout<<k<<' '<<f[k]<<' '<<g[k]<<' '<<max(f[k]+g[k]-1,f[k]+up[k])<<endl;
}
if(w[k]==2){
int ma=0;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa)ma=max(ma,f[e[i].v]);
}
ans2=max(ans2,max(ma+g[k]-1,ma+up[k]));
}
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa){
work(e[i].v,k);
}
}
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
cin>>n;
for(int i=1;i<n;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);lj(t2,t1);
}
int Min=1e9;
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
Min=min(Min,w[i]);
}
if(Min>1){printf("%d/1
",Min);return 0;}
dfs(1,0);
dfs2(1,0);up[1]=0;
//for(int i=1;i<=n;i++)cout<<i<<' '<<f[i]<<' '<<g[i]<<' '<<up[i]<<endl;
work(1,0);
ans2++;
if(ans1*2>=ans2){
printf("1/%d
",ans1);
}
else {
if(ans2%2==0){
ans2/=2;
printf("1/%d
",ans1);
}
else printf("2/%d
",ans2);
}
return 0;
}