CF1163F: Indecisive Taxi Fee

1 Indecisive Taxi Fee

2 题目描述

时间限制 \(2s\) | 空间限制 \(512M\)

给你一个 \(n\) 个点,\(m\) 条边的无向图,每条边连接点 \(u, v\),并且有个长度 \(w\)

\(q\) 次询问,每次询问给你一对 \(t, x\),表示仅当前询问下,将 \(t\) 这条边的长度修改为 \(x\),请你输出当前 \(1\)\(n\) 的最短路长度。

数据范围:

\(2≤𝑛≤2 \times 10^5, 1≤𝑚,𝑞≤2 \times 10^5\)

\(1≤𝑢_𝑖,𝑣_𝑖≤𝑛 , 1≤𝑤_𝑖≤10^9, 𝑢_𝑖≠𝑣_𝑖\)

\(1≤𝑡_𝑗≤𝑚,1≤𝑥_𝑗≤10^9\)

3 题解

容易发现一共有四种情况:改变的边不在最短路上且变大,改变的边不在最短路上且变小,改变的边在最短路上且变小,改变的边在最短路上且变大。

第一种情况非常简单,容易发现不在最短路上的边变大并不会影响答案,因此直接输出 \(dist_{1, n}\) 即可。

第二种情况稍微复杂一点点。发现此时除了原最短路之外还有一条强制经过改变了的边的路径,假如改变的边连接的是 \(u\)\(v\),边的新权值是 \(w\),那么答案就是 \(min\{dist_{1, n}, dist_{1, u} + w + dist_{v, n}, dist_{1, v} + w + dist_{u, n}\}\)

第三种情况显然是将减小的量直接减去即可。设原来的边权为 \(w_1\),新的边权是 \(w_2\),那么答案就是 \(dist_{1, n} - w_1 + w_2\)

第四种情况是最复杂的,因为求不经过最短路上某一边的最短路长度没有任何直观做法。于是我们先开始挖掘性质。

我们先找到最短路路径 \(E_1, E_2, ..., E_k\)

性质 \(1\)\(1\) 到任意节点 \(u\) 的最短路 \(D_1,D_2, ..., D_{k_2}\) 一定存在某一段可以为空的前缀与最短路路径重叠。形式化地说,就是 \(\exists ~lu \in [0, k_2], \forall ~1\le i\le lu, E_i = D_i\),并且 \(\forall ~lu< i\le min\{k_2, k\}, E_i \ne D_i\),后缀同理。

感性证明大概如下:

主要问题在于如何保证后续没有再次出现最短路径,即不存在类似于 \(11111100001111\) 的结构(设 \(1\) 为与最短路路径重叠)。容易发现,如果在 \(1\)\(u\) 的路径上存在一段突然断开,然后又回到最短路上,那么中间这一段一定可以替换成最短路上的一部分。因为如果中间这两个点之间走非最短路径更短,那么显然最短路就应该包含这段非最短路径,所以肯定不存在这样的结构。

性质 \(2\):设前缀的最后一个重叠位置为 \(lu\),后缀的第一个重叠位置为 \(ri\),那么对于边 \((u, v)\),强制经过这条边的最短路一定不经过 \([lu_u + 1, ru_v - 1]\) 这些边(这些边的编号都是指在最短路径上的,按照 \(1\)\(n\) 的路径游走顺序排列后的边的编号)。

这是因为这些边还用着最短路的边,而 \(lu_u\)\(ru_v\) 的定义就是最后一个和第一个使用最短路上边的边。所以它们中间的边一定没有被经过。

此时,此题只需要一个能够高效进行区间取 \(min\),单点查询的数据结构即可。

我们这里考虑使用线段树。

询问时只需要直接询问线段树上题目要求的叶子结点值就可以知道不走那条边的最短路径长度了。

4 代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N = 4e5 + 10;
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
#define mp make_pair
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
priority_queue<pair<int,int> > Q;
int n, m, q, u, v, w, tot, cnt, ans;
int dist1[N], dist2[N], pre[N], le[N], ri[N], ori[N * 2];
int head[N], ver[N * 2], last[N * 2], id[N * 2], edge[N * 2];
bool vis[N], p[N];
int pe[N * 2];
struct node
{
    int l, r, minn, tag;
}t[N * 8];
void pushup(int p) {t[p].minn = min(t[p * 2].minn, t[p * 2 + 1].minn);}
void pushdown(int p)
{
    if (t[p].tag != -1)
    {
        if (t[p * 2].tag != -1) t[p * 2].tag = min(t[p * 2].tag, t[p].tag);
        else t[p * 2].tag = t[p].tag;
        if (t[p * 2 + 1].tag != -1) t[p * 2 + 1].tag = min(t[p * 2 + 1].tag, t[p].tag);
        else t[p * 2 + 1].tag = t[p].tag;
        t[p * 2].minn = min(t[p * 2].minn, t[p].tag);
        t[p * 2 + 1].minn = min(t[p * 2 + 1].minn, t[p].tag);
        t[p].tag = -1;
    }
}
void build(int p, int l, int r)
{
    t[p].l = l;
    t[p].r = r;
    t[p].tag = -1;
    t[p].minn = inf;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
}
void modify(int p, int l, int r, int d)
{
    if (l > r) return ;
    if (t[p].l >= l && t[p].r <= r)
    {
        t[p].minn = min(t[p].minn, d);
        if (t[p].tag == -1) t[p].tag = d;
        else t[p].tag = min(t[p].tag, d);
        return ;
    }
    pushdown(p);
    int mid = (t[p].l + t[p].r) >> 1;
    if (l <= mid) modify(p * 2, l, r, d);
    if (r > mid) modify(p * 2 + 1, l, r, d);
}
int query(int p, int pos)
{
    if (t[p].l == t[p].r) return t[p].minn;
    pushdown(p);
    int mid = (t[p].l + t[p].r) >> 1;
    if (pos <= mid) return query(p * 2, pos);
    return query(p * 2 + 1, pos);
}
void add(int x, int y, int z, int Id)
{
    ver[++tot] = y;
    last[tot] = head[x];
    edge[tot] = z;
    id[tot] = Id;
    ori[Id] = tot;
    head[x] = tot;
}
void dijkstra(int s, int f, int d[])
{
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++) d[i] = inf;
    d[s] = 0;
    Q.push(mp(0, s));
    while (!Q.empty())
    {
        int x = Q.top().second;
        Q.pop();
        if (vis[x]) continue;
        vis[x] = 1;
        for (int i = head[x]; i; i = last[i])
        {
            int y = ver[i], z = edge[i];
            if (d[y] > d[x] + z)
            {
                d[y] = d[x] + z;
                if (id[i] > m) pre[y] = ori[id[i] - m];
                else pre[y] = ori[id[i]];
                if (f == 1 && !p[y]) le[y] = le[x];
                if (f == 2 && !p[y]) ri[y] = ri[x];
                Q.push(mp(-d[y], y));
            }
        }
    }
}
void path()
{
    int pos = 1;
    while (pos != n)
    {
        int e = id[pre[pos]], nxt = ver[pre[pos]];
        if (nxt == pos)
        {
            if (e > m) nxt = ver[ori[e - m]];
            else nxt = ver[ori[e + m]];
        }
        cnt++;
        p[pos] = 1;
        if (e > m) pe[e] = pe[e - m] = cnt;
        else pe[e] = pe[e + m] = cnt;
        pos = nxt;
        le[pos] = cnt;
        ri[pos] = cnt + 1;
    }
    p[pos] = 1;
}
signed main()
{
    memset(pe, -1, sizeof(pe));
    n = read(), m = read(), q = read();
    for (int i = 1; i <= m; i++)
    {
        u = read(), v = read(), w = read();
        add(u, v, w, i);
        add(v, u, w, i + m);
    }
    dijkstra(n, 0, dist2);
    path();
    dijkstra(1, 1, dist1);
    dijkstra(n, 2, dist2);
    build(1, 1, cnt);
    for (int i = 1; i <= m; i++)
    {
        if (pe[i] != -1) continue;
        u = ver[ori[i]], v = ver[ori[i + m]], w = edge[ori[i]];
        modify(1, le[u] + 1, ri[v] - 1, dist1[u] + w + dist2[v]);
        modify(1, le[v] + 1, ri[u] - 1, dist1[v] + w + dist2[u]);
    }
    for (int i = 1; i <= q; i++)
    {
        int x = read();
        ans = dist1[n];
        w = read();
        if (pe[x] != -1)
        {
            ans = ans - edge[ori[x]] + w;
            if (w > edge[ori[x]]) ans = min(ans, query(1, pe[x]));
        }
        else
        {
            int u = ver[ori[x]], v = ver[ori[x + m]];
            if (w < edge[ori[x]])
            {
                ans = min(ans, dist1[u] + w + dist2[v]);
                ans = min(ans, dist1[v] + w + dist2[u]);
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

欢迎关注

posted @ 2021-09-27 22:12  David24  阅读(123)  评论(0编辑  收藏  举报