HDR002C 不想爬坡

发布于 2021-09-20  3.69k 次阅读


题目链接

题意

有一个 $n$ 个点 $m$ 条边的无向图,每个点有点权 $h_i$,每条边有边权 $w_i$,让你找出一条从 $1$ 到 $n$ 的路径,在最小化路径长度的情况下最小化路径上最大点权和最小点权的差。

$n \le 5 \times 10^3,~m \le 2 \times 10^4,~h_i \le 9 \times 10^9,~w_i > 0,~\sum w_i \le 1 \times 10^{18}$

分析

先从 $1$ 开始跑一遍单源最短路求出所有点到 $1$ 的距离。

然后我们维护一个双指针,第一个指针枚举路径最小值的点权,第二个指针维护能够满足条件的最小的路径最大值的点权。判断当前的最小值和最大值的限制是否合法的方式也非常简单,从 $1$ 开始向 $n$ BFS,途中只经过能使得路径最短的边(通过判断路径两端的点到 $1$ 的距离之差是否为当前边边权即可)和满足限制的点(即点权在最小值和最大值之间),检验是否能 BFS 到 $n$ 即可。答案即为双指针过程中出现过的最小的两个点之间的差。

代码

这里提供来自出题人的 std。

#include <cstdio>
#include <algorithm>
#include <queue>
#include <memory.h>
using namespace std;
const long long inf = 0x3f3f3f3f3f3fLL;
struct line
{
    int from;
    int to;
    long long v;
    bool flag;
    int next;
};
struct line que[500005];
struct node
{
    int id;
    long long dis;
    bool operator <(const node &b)const
    {
        return dis > b.dis;
    }
};
struct point
{
    int id;
    long long height;
    bool operator <(const point &b)const
    {
        return height < b.height;
    }
};
struct point height[100005];
int cnt, headers[100005], n, m;
long long dis[100005];
bool vis[100005], ava[100005], book[100005];
void add(int from,int to,long long v)
{
    cnt++;
    que[cnt].from = from;
    que[cnt].to = to;
    que[cnt].v = v;
    que[cnt].next = headers[from];
    headers[from] = cnt;
}
void dijkstra(int s)
{
    priority_queue<node> q;
    q.push((node){s, 0});
    memset(dis, 0x3f3f, sizeof(dis));
    dis[s] = 0;
    while(!q.empty())
    {
        node tp = q.top();
        q.pop();
        if(vis[tp.id])
            continue;
        for (int i = headers[tp.id]; i;i=que[i].next)
            if(dis[que[i].to]>dis[tp.id]+que[i].v)
            {
                dis[que[i].to] = dis[tp.id] + que[i].v;
                q.push((node){que[i].to, dis[que[i].to]});
            }
    }
}
bool bfs(int s,int t)
{
    if(!ava[s] || !ava[t])
        return 0;
    queue<int> q;
    q.push(s);
    memset(book, 0, sizeof(book));
    book[s] = 1;
    while(!q.empty())
    {
        int tp = q.front();
        q.pop();
        for (int i = headers[tp]; i;i=que[i].next)
            if(que[i].flag && ava[que[i].to] && !book[que[i].to])
            {
                book[que[i].to] = 1;
                q.push(que[i].to);
            }
    }
    return book[t];
}
int main()
{
    //freopen("upsanddowns30.in","r",stdin);
    //freopen("upsanddowns30.out", "w", stdout);
    int u, v;
    long long w;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &height[i].height);
        height[i].id = i;
    }
    sort(height + 1, height + n + 1);
    for (int i = 1; i <= m; i++)
    {
        scanf("%d%d%lld", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);
    }
    dijkstra(1);
    for (int i = 1; i <= cnt;i++)
        if(dis[que[i].to]==dis[que[i].from]+que[i].v)
            que[i].flag = 1;
    printf("%lld\n", dis[n]);
    int left = 1, right = 1;
    ava[height[right].id] = 1;
    long long ans = inf;
    while(right<=n)
    {
        while(bfs(1,n) && left<right)
        {
            ans = min(ans, height[right].height - height[left].height);
            ava[height[left].id] = 0;
            left++;
        }
        right++;
        ava[height[right].id] = 1;
    }
    printf("%lld", ans);
    return 0;
}

我缓慢吐出一串啊吧啊吧并不再想说话