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
",Ans);
	printf("%.10lf
",(double)ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13642772.html