CF566C Logistical Questions 题解
目录
题目描述
给定一棵 个点的树,点有点权 ,边有边权 ,两点间的距离为边权和的 次方。
求这棵树的带权重心 ,以及所有点到 的带权距离和。
数据范围
- 。
- 。
相对或绝对误差不得超过 。
时间限制 ,空间限制 。
分析
假如当前在 ,决策往哪棵子树走最优。
假设重心从 沿着边 移动距离 ,可以得到:
:在 逼近 的过程中,带权距离和不断变小。
感性理解一下(
其实是博主不会证明):由于 和 都是下凸函数,所以 也是下凸函数。
由于下凸函数至多一个极小值点,所以 函数值单调递减。
因此我们只需从任意一个点 出发,每次往可以让带权距离和变小的方向走一步(后面会证明如果存在必唯一)即可。如果往所有方向走都在变大,就说明我们已经找到最小值了。
判断往某个方向走是否可能变小,本质上是在判断 是否成立。
显然至多只有一个 能让 。
注: 表示往 方向走带权距离和会变小,但不代表选择 点比 点更优。
接下来是一个常见套路:点分治重心移动。
我们花费 的代价,却只移动了一步,难免有些浪费。
考虑点分治,假设当前在 并且要往 移动,我们直接移动到 所在连通块的分治重心,这样候选集大小减半, 次移动后即可找到真正的带权重心。
时间复杂度 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5,inf=1e9;
int n,s,u,v,w,rt,pos,tot;
double res=1e20;
double f[maxn],g[maxn];
int a[maxn];
int head[maxn],to[2*maxn],val[2*maxn],nxt[2*maxn];
int dp[maxn],sz[maxn];
bool vis[maxn];
void addedge(int u,int v,int w)
{
nxt[++tot]=head[u],to[tot]=v,val[tot]=w,head[u]=tot;
}
void getroot(int u,int fa)
{
dp[u]=0,sz[u]=1;
for(int i=head[u];i!=0;i=nxt[i])
{
int v=to[i];
if(vis[v]||v==fa) continue;
getroot(v,u);
dp[u]=max(dp[u],sz[v]),sz[u]+=sz[v];
}
dp[u]=max(dp[u],s-sz[u]);
if(dp[u]<dp[rt]) rt=u;
}
void dfs(int u,int fa,int dep)
{
f[u]=a[u]*sqrt(dep),g[u]=a[u]*pow(dep,1.5);
for(int i=head[u];i!=0;i=nxt[i])
{
int v=to[i];
if(v==fa) continue;
dfs(v,u,dep+val[i]);
f[u]+=f[v],g[u]+=g[v];
}
}
void solve(int u)
{
vis[u]=true,dfs(u,0,0);
if(g[u]<res) res=g[u],pos=u;
for(int i=head[u];i!=0;i=nxt[i])
{
int v=to[i];
if(vis[v]) continue;
if(f[u]-2*f[v]<0)
{
s=sz[v],rt=0,getroot(v,0),solve(rt);
break;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w),addedge(v,u,w);
}
s=n,dp[0]=inf,getroot(1,0),solve(rt);
printf("%d %.10lf",pos,res);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16398236.html
标签:
图论-点分治&点分树
, 数论-导数&积分
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?