CF566C. Logistical Questions
题目大意
题解
不知道能不能过的乱搞做法:求出一次重心和二次重心,暴力判断路劲上的,从二次开始判断应该会更快,还可以加个二分
一条链就直接二分并判断相邻两个的值,往更小的那边跳
树的话就点分治算重心答案再判断临边,但如果是菊花图就炸了
设一个点的贡献时wx^1.5,其中x是距离,改成判断导数即可,走向的子树为负其他的为正
(x^1.5)'=1.5x^0.5,在算答案时即可维护
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define ld long double
//#define file
using namespace std;
int f[200001],a[400001][3],ls[200001],n,i,j,k,l,len,mn,mn2,Ans;
ld w[200001],g[200001],ans,Sum,ANS;
bool bz[200001];
void New(int x,int y,int z) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=z;}
void dfs(int n,int Fa,int t)
{
int i,mx=0;
f[t]=1;
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa && !bz[a[i][0]])
dfs(n,t,a[i][0]),f[t]+=f[a[i][0]],mx=max(mx,f[a[i][0]]);
mx=max(mx,n-f[t]);
if (mx<mn)
mn=mx,mn2=t;
}
void Dfs(int Fa,int t,ll sum)
{
int i,mx=0;
ld s;
s=w[t]*sqrt(sum);
ANS+=s*sum,Sum+=1.5*s;
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
Dfs(t,a[i][0],sum+a[i][2]);
}
void work(int n,int t)
{
ld sum=0,mx=0;
int i,mx2;
mn=n+1;
dfs(n,0,t);
t=mn2;
dfs(n,0,t);
bz[t]=1;
ANS=0;
for (i=ls[t]; i; i=a[i][1])
{
Sum=0;
Dfs(t,a[i][0],a[i][2]);
sum+=Sum;
if (Sum>mx) mx=Sum,mx2=a[i][0];
}
if (ans<0 || ans>ANS) ans=ANS,Ans=t;
if (sum-mx<mx && !bz[mx2]) work(f[mx2],mx2);
}
int main()
{
#ifdef file
freopen("CF566C.in","r",stdin);
#endif
scanf("%d",&n);
fo(i,1,n) cin>>w[i];
fo(i,1,n-1) scanf("%d%d%d",&j,&k,&l),New(j,k,l),New(k,j,l);
ans=-1,work(n,1);
printf("%d\n",Ans);
printf("%.10lf\n",(double)ans);
fclose(stdin);
fclose(stdout);
return 0;
}