分析
まず、聞かせて\(D(i、j)は\)現在の定義におけるJ、距離Iを表し、jは固定されているときに、見つけることができ、Iパスに移動し、\(Dは\)凸関数であり、それは彼は唯一の最適解があるだろうと述べました。。
次に考える(F(I)\)\私が焦点にいたとき、答えを表します。
有:\(F(I)= \ sum_ {J \ NEQ I} F(i、j)を\) 。
次に、凸関数を追加することも下に凸の関数である後ので、\(F(i)は、\)また、下に凸の関数です。
答えツリー全体が唯一の最適な位置(必ずしもノードの場合)で、かつポイントから広がるが大きくなってしまうので。
このように考慮チェーン、ビン上の2点。
そして木に、あなたは、答えは、点線が続くルートの小さい隣接ノードの方向に選出されるたびに、分割統治を指すことができます。
そして、明らかに我々は常に暴力的なコンピューティングすることはできません\(F \) 、我々はすぐに計算するためにデリバティブを利用することができます。
ご注意ください
codeforcesは長い間、二重使用しないように見えます。。
そして、最大値が設定良いと見なされます。。。
コード:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
template <class I>
inline void read(I &x){
int f=1;
char c;
for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+(c&15),c=getchar());
x*=f;
}
int n,w[N];
int head[N],nxt[2*N],ver[2*N],edge[2*N],tot=1;
inline void add(int x,int y,int z){
ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;
}
double res=0;
int rt=0,d[N],sz;
bool v[N];
void getsz(int x,int f){
d[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(v[y]||y==f) continue;
getsz(y,x);
d[x]+=d[y];
}
}
void getrt(int x,int f){
d[x]=1;
int mx=0;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(v[y]||y==f) continue;
getrt(y,x);
d[x]+=d[y];
if(d[y]>mx) mx=d[y];
}
mx=max(mx,sz-d[x]);
if(mx<=sz/2) rt=x;
}
double ds[N];
void calc(int o,int x,int fa,int dis){
res+=(double)pow(dis,1.5)*w[x];
ds[o]+=1.5*pow(dis,0.5)*w[x];
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
calc(o,y,x,dis+edge[i]);
}
}
int anss;
double ans=1e20;
void dfs(int x){
getsz(x,0);
sz=d[x];
getrt(x,0);
if(v[x]) return;
v[x=rt]=1;
res=0;
double sds=0;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
ds[y]=0;
calc(y,y,x,edge[i]);
sds+=ds[y];
}
if(ans>res) ans=res,anss=x;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(sds-2*ds[y]>=0) continue;
dfs(y);
return;
}
}
int main(){
read(n);
for(int i=1;i<=n;i++) read(w[i]);
for(int i=1;i<n;i++){
int x,y,z;
read(x),read(y),read(z);
add(x,y,z);
add(y,x,z);
}
dfs(1);
printf("%d %.7f\n",anss,ans);
return 0;
}