计蒜客模拟赛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();
}
时间: 2024-12-29 07:42:05

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

计蒜客模拟赛D1T1 蒜头君打地鼠:矩阵旋转+二维前缀和

题目链接:https://nanti.jisuanke.com/t/16445 题意: 给你一个n*n大小的01矩阵,和一个k*k大小的锤子,锤子只能斜着砸,问只砸一次最多能砸到多少个1. 题解: 将原矩阵顺时针旋转45°,二维前缀和预处理,然后枚举每一个可能砸到的正方形之和并取最大. 注:枚举的正方形的四个顶点必须是从原矩阵璇转过来的点,代码中用vis数组判断. #include <iostream> #include <stdio.h> #include <string.

后缀字符串 计蒜客模拟赛

一天蒜头君得到 nnn 个字符串 sis_isi?,每个字符串的长度都不超过 101010. 蒜头君在想,在这 nnn 个字符串中,以 sis_isi? 为后缀的字符串有多少个呢? 输入格式 第一行输入一个整数 nnn. 接下来 nnn 行,每行输入一个字符串 sis_isi?. 输出格式 输出 nnn 个整数,第 iii 个整数表示以 sis_isi? 为后缀的字符串的个数. 数据范围 对于 50%50\%50% 的数据,1≤n≤1031 \le n \le 10^31≤n≤103. 对于 1

计蒜客课程竞赛入门--蒜头学算数 流程记

蒜头的数学实在是太差了,于是老师把他关到小黑屋让他闭门修炼.老师跟他一张纸,上面一 排写着1, 2, 3...N这N个数,中间用空白分隔.老师让他在空白处填上加号或者减号.他让蒜头君求出一共有多少种加运算符的方法使得整个表达式的值为0,并输出所有 的方案.比如N=7时,1 2 3 4 5 6 7排成一排,一种插入符号的方案为1+2-3+4-5-6+7=0.是不是很有趣,快来帮蒜头君解出这题吧(*´▽`)?? 输入为一行,包含一个整数N(3≤N≤9). 输出为所有在每对数字间插入“+”或“-”后能

复习---归并排序求逆序对--计蒜客2017noip模拟赛二--蒜头君的排序

题目链接:https://nanti.jisuanke.com/t/16443 我不会矩阵快速幂,所以只拿了60分, 发现归并排序掌握的并不熟练,借此良机复习一下. 重在归并排序分治思想,要牢记! #include<iostream> #include<cstring> using namespace std; int n,m,a[30005],s[30005],ans,d[30005]; void msort(int l,int r) { if(l==r)return;//如果只

2019ICPC西安邀请赛(计蒜客复现赛)总结

开始时因为吃饭晚了一刻钟,然后打开比赛.看了眼榜单A题已经过了二十来个队伍了,宝儿就去做A. 传师说最后一题看题目像最短路,于是我就去看M了,宝儿做完之后也来陪我看.M一开始看到时以为是像   POJ的Frogger   一样,求S 到T 的路径中的最小距离最大值.后来发现对路径中走过的边数也有限制.于是又去想,然后想到把原本记录到此点最短距离的Dis[] 变成 记录到达此点所需要飞行器最低等级的Dis_Level[],这样剩下的就是普通的Dijkstra了.做完M之后比赛进行了大概一个半小时.

计蒜客38228 Max answer 单调栈 + 线段树

Max answer 与POJ 2796 Feel Good类似,但是这个题有负数,需要特殊处理一下 #include <bits/stdc++.h> #define DBG(x) cerr << #x << " = " << x << endl using namespace std; typedef long long LL; #define iall 1, n, 1 #define lrrt int l, int r,

[计蒜客NOIP模拟赛]2017.7.28Day1回顾反思总结

D1T1 打地鼠 题目链接 反思- 比赛得分-0 思考: 比赛时,以为T1是一道常规模拟题目,没怎么看数据范围.直接手动模拟,模拟完之后太自信也没有造数据Hack自己的程序.直接导致爆0.同时发现自己对二维前缀和的学习也只是在皮毛之上,没有深入思考与理解. 解题思路- 将图像旋转45°之后用二维前缀和维护,每次O(1)查询,时间复杂度O(N*N). 但是目前觉得这个图像旋转45°难以理解,打算手动模拟加深理解. 标程 #include<bits/stdc++.h> using namespac

计蒜客普及组模拟赛

今天没事闲的看到计蒜客有个普及组模拟赛,就当练了练手去打了,成绩低的可怜...400分崩成280分AK梦想化作泡影 第一题 同学的爱好 链接:https://nanti.jisuanke.com/t/17291 小学应用题难度?大概画个图就能懂,把每个部分都标上号,算出a,b,c,d,e,f的部分,进行运算就行了. 不多解释了,直接上代码 #include<iostream> #include<cstdio> #include<algorithm> #include&l

计蒜客 作弊揭发者(string的应用)

鉴于我市拥堵的交通状况,市政交管部门经过听证决定在道路两侧安置自动停车收费系统.当车辆驶入车位,系统会通过配有的摄像头拍摄车辆画面,通过识别车牌上的数字.字母序列识别车牌,通过连接车管所车辆信息数据库确认车辆,进行扣费. 斗智斗勇的好戏一般从此处展开… 一些车主通过在停车时遮挡车牌上的一个或多个数字.字母序列,来阻碍识别系统的识别工作,以此逃避停车费用的缴纳. 车主这简直是用轻轻的一挡搞出来一个世界难题有木有?!管理是一方面,技术解决才是王道啊. 这么难的项目不得不交给计蒜客实验室了.D 神负责