计蒜客模拟赛D1T2 蒜头君的树:树上节点之间最短距离和

题目链接:https://nanti.jisuanke.com/t/16446

题意:

  给你一棵有n个节点的树以及每条边的长度,输出树上节点之间的最短距离和。然后进行m次操作,每次操作更改一条边的长度,分别输出每次操作后树上节点之间的最短距离和。

 

题解:

  最短距离和 = ∑(树上每一条边被最短路经过的次数 * 这条边的长度)

  一个节点到它父节点的边被经过的次数 = 该节点以及它的子孙的节点个数 * 除了该节点和它子孙之外的所有节点总个数

  

  每一个节点以及它子孙节点的个数总和用一遍dfs保存在num数组中,然后算出每个sum[i] = num[i] * (n - num[i]),就可以求出在没有进行任何操作时的最短距离和。

  对于每一次操作将第a个节点到它父节点的边长由原来的len[a]改为b,则将原来的最短距离和dis改为dis + (b - len[a])并输出,同时将len[a]改为b即可。

  预处理&计算操作前的最短距离和的复杂度为O(N),m次询问复杂度O(M),总复杂度为O(N+M)。

  注:本题会爆int,Ctrl+R全换成long long。。。

 

AC Code:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#define MAX_N 100005

using namespace std;

int n,m;
long long dis=0;
long long len[MAX_N];
long long num[MAX_N];
long long sum[MAX_N];
vector<int> edge[MAX_N];

void read()
{
    memset(len,0,sizeof(len));
    cin>>n;
    for(int i=2;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        edge[x].push_back(i);
        len[i]=y;
    }
}

long long dfs(int now)
{
    long long tot=1;
    for(int i=0;i<edge[now].size();i++)
    {
        tot+=dfs(edge[now][i]);
    }
    num[now]=tot;
    return tot;
}

void cal_sum()
{
    for(int i=1;i<=n;i++)
    {
        sum[i]=num[i]*(n-num[i]);
    }
}

void cal_dis()
{
    for(int i=1;i<=n;i++)
    {
        dis+=sum[i]*len[i];
    }
}

void solve()
{
    dfs(1);
    cal_sum();
    cal_dis();
    cout<<dis<<endl;
    cin>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        dis+=(b-len[a])*sum[a];
        len[a]=b;
        cout<<dis<<endl;
    }
}

int main()
{
    read();
    solve();
}

 

转载于:https://www.cnblogs.com/Leohh/p/7261131.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用模拟退火算法计算西宁市到海东市的最短距离的 MATLAB 代码示例: ```matlab % 西宁市和海东市的经纬度坐标 x = [101.784450, 102.103681]; y = [36.623847, 36.502916]; % 计算两个城市之间的距离(单位:千米) dist = pdist([x', y'], 'euclidean') * 111; % 定义模拟退火算法的参数 T0 = 100; % 初始温度 Tf = 1e-8; % 终止温度 alpha = 0.99; % 降温速率 max_iter = 1e5; % 最大迭代次数 % 初始解为两个城市之间的直线距离 x0 = dist; % 模拟退火算法求解最短距离 best_x = x0; best_f = f(x0); T = T0; iter = 1; while T > Tf && iter < max_iter % 产生新解 x_new = x0 + randn() * T; % 计算新解的目标函数值 f_new = f(x_new); % 判断是否接受新解 if f_new < best_f best_x = x_new; best_f = f_new; end delta_f = f_new - f(x0); if delta_f < 0 || rand() < exp(-delta_f / T) x0 = x_new; end % 降温 T = T * alpha; iter = iter + 1; end % 输出结果 fprintf('最短距离为 %f 千米\n', best_f); % 目标函数:计算两个城市之间的距离 function fval = f(x) fval = pdist([x', y'], 'euclidean') * 111; end ``` 这个示例代码中,我们首先计算了西宁市和海东市的经纬度坐标,并根据经纬度计算了两个城市之间的距离。接着,我们使用模拟退火算法求解最短距离,其中目标函数为两个城市之间的距离。最后,输出最短距离的结果。 请注意,这个示例代码中使用的经纬度坐标和两个城市之间的距离只是作为演示用途,实际应用中需要使用更准确的数据。此外,模拟退火算法的性能也受到参数的影响,需要根据具体问题进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值