首页 > 其他分享 >YBTOJ 5.4例3 最长距离 题解

YBTOJ 5.4例3 最长距离 题解

时间:2023-04-12 14:23:09浏览次数:40  
标签:cnt 5.4 val idx int 题解 son YBTOJ dis

挂大分!!!!!!
1.一定要看清提干有没有多测
2.多测不清空 爆零两行泪
3.同时线性更新最大值和次大值时记得最大值更新要同时把旧的最大值给次大值


题解

首先可以想到一个最暴力的暴力 : 对于每一个点 暴力枚举所有的点跑LCA 复杂度 \(O(n^2logn)\) 显然会炸
然后就有一个优化一点的暴力 :显然有可能成为最长距离的结点一定是叶节点 所以暴力枚举所有叶节点就行 但是显然复杂度没啥大优化

然后再想想 发现对于每个点 所枚举的叶节点无非就两类:一类在它的子树内 一类不在
在子树内的结点可以用一个显而易见的树形dp解决 来看不在子树内的点
不难发现 对于不在子树内的点 显然当前点要跳到某个祖先 然后再下去到这个祖先内的最远点

(说句题外话 有这个就可以写一个 \(O(n^2)\) 的暴力 即暴力跳祖先枚举最远点 我不知道能不能过())

那么再往下想 就可以发现我们可以dp维护出这个点上面这些所有祖先的最大值然后进行转移
然后就可以 \(O(n)\) 了!!!

当然这里需要注意一些细节问题 因为跳祖先是要找一个折一下的路径 所以这个点本身不能在那个祖先结点的最远点所在的子树内
所以我们需要额外维护出每个节点向下能到达的次远点 然后针对这个情况进行转移

设 \(f[i][0/1/2]\) 表示编号为i的结点向下最远距离/向下次远距离/向上再折下去的最远距离
设 \(idx[i]\) 表示编号为i的结点的最远点所在的子树的根节点的编号
对于第一次dp 我们有:
\(f[i][0] = max(f[son[i]][0] + dis[i][son[i])\)
$f[i][1] = 次大值(f[son[i]][0] + dis[i][son[i]]) $

对于第二次dp 我们有:
\(f[son[i]][2] = max(f[i][0], f[i][2]) + dis[i][son[i]] (son[i] != idx[i])\)
\(f[son[i]][2] = max(f[i][1], f[i][2]) + dis[i][son[i]] (son[i] == idx[i])\)

完整代码如下:

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int N = 1e4 + 0721;
int head[N], to[N], nxt[N], dis[N], cnt;
int idx[N];
ll f[N][3];
int n;

inline void cmb(int x, int y, int z) {
    to[++cnt] = y;
    dis[cnt] = z;
    nxt[cnt] = head[x];
    head[x] = cnt;
}

void dfs1(int x) {
    ll maxn = 0;
    ll cmax = 0;
    for (int i = head[x]; i; i = nxt[i]) {
        int y = to[i];
        dfs1(y);
        ll val = f[y][0] + dis[i];
        if (val > maxn) {
        	cmax = maxn;
            idx[x] = y;
            maxn = val;
        } else if (val >= cmax) cmax = val;
    }
    f[x][0] = maxn;
    f[x][1] = cmax;
}

void dfs2(int x) {
    for (int i = head[x]; i; i = nxt[i]) {
        int y = to[i];
        if (y == idx[x])
            f[y][2] = max(f[x][1], f[x][2]) + dis[i];
        else
            f[y][2] = max(f[x][0], f[x][2]) + dis[i];
        dfs2(y);
    }
}

int main() {
    while (scanf("%d", &n) != EOF) {
        cnt = 0;
        for (int i = 1; i <= n; ++i) head[i] = 0;
        for (int i = 1; i <= n; ++i) f[i][0] = f[i][2] = f[i][1] = 0;

        for (int i = 2; i <= n; ++i) {
            int fa, v;
            scanf("%d%d", &fa, &v);
            cmb(fa, i, v);
        }

        dfs1(1);
        dfs2(1);
//      for (int i = 1; i <= n; ++i) cout << i << " " << f[i][0] << " " << f[i][1] << " " << f[i][2] << endl;

        for (int i = 1; i <= n; ++i) printf("%lld\n", max(f[i][0], f[i][2]));
    }

    return 0;
}

标签:cnt,5.4,val,idx,int,题解,son,YBTOJ,dis
From: https://www.cnblogs.com/Steven24/p/17307691.html

相关文章

  • grafana+influxdb2+jmeter5.4搭建服务监控平台
    一.grafana+influxdb2安装通过docker的方式,创建个目录,写docker-compse1.docker-compse.ymlversion:"3"services:influxdb:image:influxdb:2.2.0container_name:influxdbports:-"8086:8086"grafana:image:grafana/grafana......
  • CF698F Coprime Permutation 题解
    题意给定一个未填满的数组\(p\),求有多少种\(1\simn\)的排列\(p\)满足对于任意\(i<j\),都有\([\gcd(i,j)=1]=[\gcd(p_i,p_j)=1]\),答案对\(10^9+7\)取模。题解部分参考这篇题解(感觉这篇题解应该是目前为止最详细的吧)。记\(P\)为\([1,n]\)中所有素数与\(1\)构成......
  • Codeforces Round 864 (Div. 2) 题解
    A.LiHuaandMaze题目保证了两个点的哈密顿距离至少为\(2\),所以他们不会相邻。只要有点在角上答案就是\(2\),在边上但不在角上就是\(3\),否则就是\(4\)。#include<bits/stdc++.h>#include<ext/pb_ds/assoc_container.hpp>#include<ext/pb_ds/tree_policy.hpp>#includ......
  • 「题解」ABC296Ex Unite
    考虑一行一行往下dp,一个状态需要记录每个格子是否是黑色,对于黑色还有记录其并查集。爆搜跑一下本质不同状态数不是很多,dp就行了。\(m=7\)的时候状态数只有324.#include<cstdio>#include<vector>#include<queue>#include<cstring>#include<iostream>#include<algorithm>......
  • 15.4折半查找原理及实战
    #include<stdio.h>#include<stdlib.h>#include<time.h>typedefintElemType;typedefstruct{ElemType*elem;//整型指针intTableLen;//存储动态数组里边元素的个数}SSTable;//init进行了随机数生成,折半查找没有使用哨兵voidST_Init(SSTable&ST,i......
  • CF1525F 题解
    题意有一个\(n\)个点的DAG,现在有\(k\)波进攻,第\(i\)波有\(i\)个人,它们每个人会选择一条DAG上的路径,并占领这个路径上的所有点,路径之间是不能相交的。第\(i\)波进攻前可以做一些准备,可以花\(1\)秒关闭某个点的所有入边,或关闭某个点的所有出边。第\(i\)波进攻有个......
  • COMP326问题解答
    COMP326Assignment2(15%ofthefinalmark)Due18thApril2023Pleasesubmityoursolutionselectronically(inPDFformat)onCanvasPleasebeawareoftheUniversityguidelinesonplagiarismandcollusion.Themarksforlatesubmissionswillbeaffectedin......
  • ubuntu因为升级自动更新内核而重启无法进入图形界面问题解决
    ubuntu因为升级自动更新内核而重启无法进入图形界面问题解决。我使用的ubuntu版本是22.04LTS。经常因为系统更新软件而自动更新内核,又因为我的PC上安装了NVIDIA的显卡,这个卡对应的驱动是NVIDIA-Linux-x86_64-525.89.02.run。这个驱动要从官网上下载安装,而ubuntu系统自带的驱动是......
  • 项目现状问题解决方案
    成果清单的实时统计:可以通过使用在线协作平台或者项目管理软件来实现成果清单的实时更新与统计。这些工具可以帮助团队成员在同一个平台上实时记录产出和进度,并且可以通过图表和报表等形式呈现出来,方便团队和领导进行跟踪和管理。问题登记的规范化:可以建立一个问题登记和解决......
  • P9203 时效「月岩笠的诅咒」 题解
    题目传送门题目大意判断每次经过以下操作其一后,\(a\)与\(b\)是否相等:将\(a\)加上\(1\),即\(a\getsa+1\);将\(b\)加上\(1\),即\(b\getsb+1\)。解题思路\(a\)和\(b\)都是每次加\(1\),所以如果它们相等,那它们的小数部分应该是相等的,所以问题就变成了判断\(a\)......