Mag
\(设l(x)表示长度,m(x)表示乘积\)
\(考虑没有1的情况\)
\(连接x,y两条链\)
\(设\)
\[\dfrac{m(x)}{l(x)}<\dfrac{m(y)}{l(y)}
\]
\(则\)
\[\dfrac{m(x)}{m(y)}<\dfrac{l(x)}{l(y)}
\]
\(若连接后优\)
\[\dfrac{m(x)m(y)}{l(x)+l(y)}<\dfrac{m(x)}{l(x)}
\]
\[\dfrac{m(y)}{l(x)+l(y)}<\dfrac{1}{l(x)}
\]
\[l(x)m(y)<l(x)+l(y)
\]
\[(m(y)-1)<\dfrac{l(y)}{l(x)}<\dfrac{m(y)}{m(x)}
\]
\[(m(x)m(y))-m(x)-m(y)+1<1
\]
\[(m(x)-1)(m(y)-1)<1
\]
\(m(x),m(y)>1显然不成立\)
\(考虑一条的链x\)
\((1)若x是M>1,两边有许多1\)
\(设M左边有l个1,右边有r个1,规定l\leq r(其实r>l等价)\)
\(若要选M\)
\[\dfrac{M}{l+r+1}<\dfrac{1}{r}
\]
\[M<1+\dfrac{l+1}{r}
\]
\(当且仅当l=r,M=2时,这样选最优\)
\((2)若x是M>1,N>1相连,中间与两边夹着许多1\)
\(设M左N右\)
\(设l为M左边1的个数,r为N右边1的个数,m为中间1的个数,k=max(l,m,r)\)
\(若要选该链\)
\[\dfrac{NM}{l+r+m+2}<\dfrac{1}{k}
\]
\[NMk<l+r+m+2
\]
\[\because N\geq2,M\geq2
\]
\[\therefore l+r+m+2>NMk\geq4k
\]
\(当且仅当l=r=m满足,即1-2-1-2-1,但1-2-1明显更优\)
\((3)若x是M>1,N>1相连,两边夹着许多1,中间没有\)
\(设M左N右\)
\(设l为M左边1的个数,r为N右边1的个数,k=max(l,r)\)
\(若要选该链\)
\[\dfrac{NM}{l+r+2}<\dfrac{1}{k}
\]
\[\therefore l+r+2>NMk\geq4k
\]
\(明显不成立\)
\(由(2)(3)可以推广到一般\)
\(结论:(1)无1选最小\)
\((2)有一选最长的1或1中夹着一个2\)
\(考虑实现\)
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
template<typename ll=int>
class Frac
{
private:
ll abs(const ll& x)const{return x<0?-x:x;}
ll gcd(const ll& x,const ll& y)const{return y?gcd(y,x%y):x;}
Frac reduce()
{
bool flag=0;
if(a<0&&b<0) a=-a,b=-b;
if(a<0) a=-a,flag=1;
if(b<0) b=-b,flag=1;
ll ggcd=gcd(a,b);
a/=ggcd;
b/=ggcd;
if(flag) a=-a;
return *this;
}
void swap(){std::swap(a,b);}
Frac _swap(const Frac& t)const{return Frac(t.b,t.a);}
ll FastPow(ll x,ll p,ll mod)const
{
ll ans=1,bas=x;
for(;p;bas=bas*bas%mod,p>>=1)
if(p&1) ans=ans*bas%mod;
return ans;
}
public:
ll a,b;
Frac(ll A=0,ll B=1){a=A,b=B;}
void red()
{
bool flag=0;
if(a<0&&b<0) a=-a,b=-b;
if(a<0) a=-a,flag=1;
if(b<0) b=-b,flag=1;
ll ggcd=gcd(a,b);
a/=ggcd;
b/=ggcd;
if(flag) a=-a;
return;
}
void show()const{std::cout<<a<<'/'<<b<<endl;}
ll to_int(const ll& mod=998244353)const{return a*FastPow(b,mod-2,mod)%mod;}
Frac abs()const{return Frac(abs(a),abs(b));}
Frac operator =(const Frac& t){return a=t.a,b=t.b,t;}
bool operator ==(const Frac& t)const{Frac A(*this),B(t);return (A.reduce().a==B.reduce().a)&&(A.b==B.b);}
bool operator !=(const Frac& t)const{Frac A(*this),B(t);return (A.a!=B.a)||(A.b!=B.b);}
bool operator >(const Frac& t)const{Frac A(*this),B(t);ll ggcd=gcd(A.reduce().b,B.reduce().b);return B.b/ggcd*A.a>A.b/ggcd*B.a;}
bool operator <(const Frac& t)const{Frac A(*this),B(t);ll ggcd=gcd(A.reduce().b,B.reduce().b);return B.b/ggcd*A.a<A.b/ggcd*B.a;}
bool operator >=(const Frac& t)const{Frac A(*this),B(t);ll ggcd=gcd(A.reduce().b,B.reduce().b);return B.b/ggcd*A.a>=A.b/ggcd*B.a;}
bool operator <=(const Frac& t)const{Frac A(*this),B(t);ll ggcd=gcd(A.reduce().b,B.reduce().b);return B.b/ggcd*A.a<=A.b/ggcd*B.a;}
Frac operator +(const Frac& t)const{ll ggcd=gcd(b,t.b);return Frac(b/ggcd*t.a+t.b/ggcd*a,b/ggcd*t.b).reduce();}
Frac operator +=(const Frac& t){return *this=*this+t;}
Frac operator *(const Frac& t)const{return Frac(a*t.a,b*t.b).reduce();}
Frac operator *=(const Frac& t){return *this=*this*t;}
Frac operator -(const Frac& t)const{return (*this+Frac(-t.a,t.b)).reduce();}
Frac operator -=(const Frac& t){return *this=*this-t;}
Frac operator /(const Frac& t)const{return (t._swap(t)*(*this)).reduce();}
Frac operator /=(const Frac& t){return *this=*this/t;}
Frac operator -()const{return Frac(-a,b);}
};
const int MAXN=1e6+5;
int n;
Frac<int>cl0(0,1);
Frac<int>cl1(1,1);
Frac<int>cl2(2,1);
Frac<int>INF(0x3f3f3f3f,1);
vector<int>g[MAXN];
Frac<int>res;
Frac<int>dp1[MAXN];
Frac<int>dp2[MAXN];
int val[MAXN];
int x,y;
void print(Frac<int>re)
{
re.red();
re.show();
return;
}
Frac<int>Min(Frac<int>x,Frac<int>y)
{
return x<y?x:y;
}
Frac<int>Max(Frac<int>x,Frac<int>y)
{
return x>y?x:y;
}
void dfs(int x,int f)
{
bool sf=0;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
sf=1;
dfs(v,x);
if(val[x]==1)
{
dp1[x]=Max(dp1[x],dp1[v]+cl1);
dp2[x]=Max(dp2[x],dp2[v]+cl1);
}
if(val[x]==2)
{
dp2[x]=Max(dp2[x],dp1[v]+cl1);
}
}
if(!sf)
{
if(val[x]==1)
{
dp1[x]=cl1;
}
if(val[x]==2)
{
dp2[x]=cl2;
}
return;
}
int fir1=0,fir2=0,sec1=0,sec2=0;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(f==v)
{
continue;
}
if(dp2[v]>=dp2[fir2])
{
sec2=fir2;
fir2=v;
}
else if(dp2[v]>dp2[sec2])
{
sec2=v;
}
if(dp1[v]>=dp1[fir1])
{
sec1=fir1;
fir1=v;
}
else if(dp1[v]>dp1[sec1])
{
sec1=v;
}
}
if(val[x]==1)
{
if(fir1==fir2)
{
res=Min(res,(cl2/(dp1[sec1]+dp2[fir2]+cl1)));
res=Min(res,(cl2/(dp1[fir1]+dp2[sec2]+cl1)));
}
else
{
res=Min(res,(cl2/(dp1[fir1]+dp2[fir2]+cl1)));
}
res=min(res,(cl1/(dp1[fir1]+dp1[sec1]+cl1)));
}
if(val[x]==2)
{
res=min(res,(cl2/(dp1[fir1]+dp1[sec1]+cl1)));
// print((cl2/(dp1[fir1]+dp1[sec1]+cl1)));
// printf("%d %d\n",fir1,sec1);
// print(dp1[fir1]);
// print(dp1[sec1]);
}
}
int main() {
res=INF;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
dp1[i]=cl0;
dp2[i]=cl0;
Frac<int>dsf(val[i],1);
res=Min(res,dsf);
}
//print();
//printf("\n");
dfs(1,0);
print(res);
}