牛客多校1-H Longest Path

本文介绍了一种结合树型动态规划与斜率优化技巧解决特定类型最优化问题的方法。通过对树上两点间路径定义一种特殊的距离度量,文章详细阐述了如何计算每个节点到其他节点的最大路径和。此过程涉及向下DP的直接应用及向上DP中斜率优化的巧妙使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意一棵树,两点的路径和d(u,v)为相邻边权差的平方和的总和。对于每个点,求maxvd(u,v)maxvd(u,v)

思路 经典树型DP+斜率优化

我们考虑每个点向上走与向下走能获得的答案,那么每个点总的答案就是max(up[i],down[i])max(up[i],down[i]) 向下走的答案是容易求得的,只需要从叶子向上DP即可。向上走的答案就要麻烦一些了。对于一个点

up[i]=max(up[ifather]+(c[i]c[ifather])2,down[ibrother]+(c[i]c[ibrother])2)up[i]=max(up[ifather]+(c[i]−c[ifather])2,down[ibrother]+(c[i]−c[ibrother])2)

这里出现了二次项,是一个经典的斜率优化DP。考虑

max{down[ibrother]+(c[i]c[ibrother])2}max{down[ibrother]+(c[i]−c[ibrother])2}

把这个式子拆开来, 我们要从j转移而不是从k转移的条件是

(down[j]+c[j]2)(down[k]+c[k]2)>2c[i](c[j]c[k])(down[j]+c[j]2)−(down[k]+c[k]2)>2∗c[i]∗(c[j]−c[k])

对于每个状态,将其看作一个point(c[j],c[j]2+down[j])point(c[j],c[j]2+down[j]) 则该式子可看作c[i]c[i] <= pjpjpkpk 两点的斜率(c[j]>c[k]c[j]>c[k]的情况下), up[i]将从j转移过来。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;

const int N = 1e5 + 10;
ll sqr(ll x){
    return x*x;
}
struct point{
    ll x,y;
    int id;
    bool operator < (point &b){
        return x < b.x;
    }
    point operator - (point &p){
        return {x - p.x, y - p.y};
    }
};
ll dot(point a, point b) {
    return a.x * b.x + a.y * b.y;
}
ll cross(point a, point b) {
    return a.x * b.y - a.y * b.x;
}
vector<point>G[N];
ll down[N], up[N], ans[N], c[N];

void dfs1(int u, int fa){
    for (point e : G[u]){
        int v = e.x, w = e.y;
        if (v == fa) continue;
        c[v] = w;
        dfs1(v, u);
        if (fa) {
            down[u] = max(down[u], down[v] + sqr(c[v] - c[u]));
            ans[fa] = max(ans[fa], down[u]);
        }
    }
}

point ch[N], son[N];
int top, m;
void dfs2(int u, int fa){
    m = 0;
    for (point e : G[u]){
        int v = e.x;
        if (v == fa) continue;
        if (fa) up[v] = max(up[v], up[u] + sqr(c[v] - c[u]));
        son[m++] = {c[v], down[v] + sqr(c[v]), v};
    }
    sort(son, son + m);
    top=0;
    for (int i = 0; i < m; i++){
        int id = son[i].id;
        point vec = {-2 * c[id], 1};
        while(top > 1 && dot(vec, ch[top - 1]) <= dot(vec, ch[top - 2])) top--;
        if (top) up[id] = max(up[id], dot(vec, ch[top - 1]) + sqr(c[id]));
        while(top > 1 && cross(ch[top - 1] - ch[top - 2], son[i] - ch[top - 2]) >= 0) top--;
        ch[top++] = son[i];
    }
    top = 0;
    for (int i = m - 1; i >= 0; i--){
        int id = son[i].id;
        point vec={-2 * c[id], 1};
        while(top > 1 && dot(vec, ch[top - 1]) <= dot(vec, ch[top - 2])) top--;
        if (top) up[id] = max(up[id], dot(vec, ch[top - 1]) + sqr(c[id]));
        while(top > 1 && cross(ch[top - 1] - ch[top - 2], son[i] - ch[top - 2]) <= 0) top--;
        ch[top++] = son[i];
    }
    for (point e : G[u]){
        int v = e.x;
        if (v == fa) continue;
        dfs2(v, u);
    }
}
int main(){
    int n;
    while(~scanf("%d", &n)){
        for (int i = 1;i <= n; i++) {
            G[i].clear();
            ans[i] = down[i] = up[i] = c[i] = 0;
        }
        for (int i = 1, x, y, z; i < n; i++){
            scanf("%d%d%d", &x, &y, &z);
            G[x].push_back({y, z});
            G[y].push_back({x, z});
        }
        dfs1(1, 0);
        dfs2(1, 0);
        for (int i = 1;i <= n; i++) printf("%lld\n", max(ans[i], up[i]));
    }
}
### 关于京东牛客网技术运维工程师笔试题目与经验 #### 笔试内容概述 技术运维工程师的笔试通常会涉及计算机基础、网络协议、操作系统原理以及实际问题解决能力等方面的知识。根据以往的经验,京东的技术运维工程师笔试可能包括但不限于以下几个方面[^1]: - **基础知识**:数据结构与算法的基础应用,例如数组、链表的操作,排序算法的选择与实现。 - **网络知识**:TCP/IP 协议栈的理解,HTTP/HTTPS 的工作流程,DNS 解析过程等。 - **Linux 操作系统**:Shell 编程、进程管理、文件权限控制等内容。 - **数据库操作**:SQL 查询语句优化,索引设计,事务处理机制。 以下是几个常见的考察方向及其对应的示例问题: #### 数据结构与算法实例 ```python def find_missing_number(nums): n = len(nums) + 1 expected_sum = n * (n + 1) // 2 actual_sum = sum(nums) return expected_sum - actual_sum ``` 此函数用于在一个长度为 `n` 的列表中找到缺失的一个整数,假设该列表原本应包含从 1 到 `n` 的连续正整数序列[^1]。 #### Linux Shell 实现脚本 编写一个简单的 Bash 脚本来监控磁盘空间并发送警告邮件给管理员: ```bash #!/bin/bash THRESHOLD=90 CURRENT=$(df / | grep / | awk '{ print $5}' | sed 's/%//g') if [ "$CURRENT" -gt "$THRESHOLD" ]; then echo "Warning: Disk space is low." | mail -s "Disk Space Alert" admin@example.com fi ``` 这段代码展示了如何通过命令行工具检测根目录下的可用存储容量,并在超过设定阈值时触发警报通知[^3]。 #### SQL 查询技巧 对于大规模关系型数据库中的性能调优而言,合理创建复合索引可以显著提升查询效率。比如,在一张记录用户活动日志的大表里查找特定时间段内的活跃用户数量时,应该考虑对日期字段建立覆盖索引来减少全表扫描带来的开销。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值