CF449B Jzzhu and Cities 题解

发布于 2023-08-25  382 次阅读


Jzzhu and Cities

题面翻译

题意简述

$n$ 个点,$m$ 条带权边的无向图,另外还有$k$ 条特殊边,每条边连接$1$ 和$i$ 。

问最多可以删除这$k$ 条边中的多少条,使得每个点到$1$ 的最短距离不变。

输入

第一行3个数字$n,m,k$

下面$m$ 行,每行3个数字$u_i,v_i,x_i(u_i\not= v_i)$

再下面$k$ 行,每行两个数字$s_i,y_i$ ,代表连接$1-s$ 的边,权值为$y_i$

数据范围

$1 ≤ u_i,v_i,s_i ≤n ≤ 10^5$

$1 ≤ k ≤ 10^5$

$1 ≤ m ≤ 3\times 10^5$

$1 ≤ x_i,y_i ≤ 10^9$

感谢@wmxwmx 提供的翻译

题目描述

Jzzhu is the president of country A. There are $ n $ cities numbered from $ 1 $ to $ n $ in his country. City $ 1 $ is the capital of A. Also there are $ m $ roads connecting the cities. One can go from city $ u{i} $ to $ v{i} $ (and vise versa) using the $ i $ -th road, the length of this road is $ x{i} $ . Finally, there are $ k $ train routes in the country. One can use the $ i $ -th train route to go from capital of the country to city $ s{i} $ (and vise versa), the length of this route is $ y_{i} $ .

Jzzhu doesn't want to waste the money of the country, so he is going to close some of the train routes. Please tell Jzzhu the maximum number of the train routes which can be closed under the following condition: the length of the shortest path from every city to the capital mustn't change.

输入格式

The first line contains three integers $ n,m,k $ $ (2<=n<=10^{5}; 1<=m<=3·10^{5}; 1<=k<=10^{5}) $ .

Each of the next $ m $ lines contains three integers $ u{i},v{i},x{i} $ $ (1<=u{i},v{i}<=n; u{i}≠v{i}; 1<=x{i}<=10^{9}) $ .

Each of the next $ k $ lines contains two integers $ s{i} $ and $ y{i} $ $ (2<=s{i}<=n; 1<=y{i}<=10^{9}) $ .

It is guaranteed that there is at least one way from every city to the capital. Note, that there can be multiple roads between two cities. Also, there can be multiple routes going to the same city from the capital.

输出格式

Output a single integer representing the maximum number of the train routes which can be closed.

样例 #1

样例输入 #1

5 5 3
1 2 1
2 3 2
1 3 3
3 4 4
1 5 5
3 5
4 5
5 5

样例输出 #1

2

样例 #2

样例输入 #2

2 2 3
1 2 2
2 1 3
2 1
2 2
2 3

样例输出 #2

2

题解

本题有特殊边这一个条件,乍一看好像不知道如何下手,我们考虑什么时候可以删特殊边。我们先把所有边存一起,当我们可以删去一条特殊边时,要么这条特殊边就是是最短方案中的一种,要么没有最短方案优,没有其他的情况了。此外,如果一条特殊边可以被删掉,那么一定有比他更优或者一样优的方案,因此删掉这条边不会影响其他答案。

这里还要把特殊边处理一下,留下所有相同的特殊边中最短的,可以省时间,剩下的就是最短路计数了。

Code

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define endl '\n'
using namespace std;

const int maxn = 300005;
int n, m, k, dis[maxn], ans, spe[maxn], cnt[maxn];
bool vis[maxn];
vector<pair<int, int>> edge[maxn * 3];

void dijkstra()
{
    memset(dis, 0x3f3f, sizeof(dis));
    dis[1] = 0;
    priority_queue<pair<int, int>> q;
    q.push({0, 1});
    while (!q.empty())
    {
        int now = q.top().second;
        q.pop();
        if (vis[now])
            continue;
        vis[now] = true;
        for (auto i : edge[now])
        {
            int to = i.first;
            if (dis[to] > dis[now] + i.second)
            {
                dis[to] = dis[now] + i.second;
                cnt[to] = 1;
                q.push({-dis[to], to});
            }
            else if (dis[to] == dis[now] + i.second)
                cnt[to]++;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> m >> k;
    for (int i = 1, u, v, x; i <= m; i++)
    {
        cin >> u >> v >> x;
        edge[u].push_back({v, x});
        edge[v].push_back({u, x});
    }
    memset(spe, -1, sizeof(spe));
    for (int i = 1, v, x; i <= k; i++) // 如果有相同的边,记录最短的那条
    {
        cin >> v >> x;
        if (spe[v] != -1)
        {
            ans++;
            if (spe[v] > x)
                spe[v] = x;
        }
        else
            spe[v] = x;
    }
    for (int i = 1; i <= n; i++)
    {
        if (spe[i] != -1)
        {
            edge[1].push_back({i, spe[i]});
            edge[i].push_back({1, spe[i]});
        }
    }
    dijkstra();
    for (int i = 1; i <= n; i++)
    {
        if (spe[i] == -1)
            continue;
        if (dis[i] < spe[i])
            ans++;
        if (dis[i] == spe[i] && cnt[i] > 1)
            ans++;
    }
    cout << ans << endl;
    return 0;
}

end