重返天梯-L3-028 森森旅游 (30 分)

重返天梯-L3-028 森森旅游 (30 分) ,第1张

题目描述

重返天梯-L3-028 森森旅游 (30 分)原题链接
森森决定从 1 号城市出发,到 n 号城市去。


他打算在出发前准备一些现金,并在途中的某个城市将剩余现金 全部 换成旅游金后继续旅游,直到到达 n 号城市为止。


当然,他也可以选择在 1 号城市就兑换旅游金,或全部使用现金完成旅程。


对每一次汇率调整,在对应的一行中输出调整后森森至少需要准备多少现金,才能按他的计划从 1 号城市旅行到 n 号城市。


再次提醒:如果森森决定在途中的某个城市兑换旅游金,那么他必须将剩余现金全部、一次性兑换,剩下的旅途将完全使用旅游金支付。


题目分析

刚拿到题目的时候,在分析到底应该在哪个点全部兑换成旅游金。



我们将题目中描述的旅程分为两段,在p点之前,全部使用现金;在p点之后,全部使用旅游金。


然后把每个点作为p点遍历一次就好了。


从数据范围判断出,要用堆优化djikstra( O ( m l o g n ) O(mlogn) O(mlogn))

分段计算现金,需要把后半段的旅游金按城市汇率进行上取整转换为现金(a/b=(a+b-1)/b)。


multiset进行维护,动态的删除保留最小值

  • s.erase(s.find(xxx))
C++
#include 
#include 
#include 
#include 

using namespace std;

typedef long long LL;
typedef pair<LL, int> PII; // 距离要开成LL

const int N = 1e5 + 10, M = 200010 * 2; // 双向边
const LL INF = 0x3f3f3f3f3f3f3f3fll;

int n, m, q;
// 双图
int h1[N], h2[N], e[M], ne[M], w[M], idx;
LL dist1[N], dist2[N];
bool st[N];
int ratio[N];

void add(int h[], int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
// 堆优化dijkstra
void dijkstra(LL dist[], int h[], int start) {
    memset(dist, 0x3f, sizeof dist1);
    memset(st, 0, sizeof st);
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, start});
    dist[start] = 0;
    
    while(heap.size()) {
        auto t = heap.top();
        heap.pop();
        
        int ver = t.second;
        
        if (st[ver]) continue;
        st[ver] = true;
        
        for (int i = h[ver]; ~i; i = ne[i]) {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i]) {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }
}


int main() {
    scanf("%d%d%d", &n, &m, &q);
    memset(h1, -1, sizeof h1);
    memset(h2, -1, sizeof h2);
    while (m--) {
        int a, b, c, d;
        scanf("%d%d%d%d", &a, &b, &c, &d);
        add(h1, a, b, c), add(h2, b, a, d);
    }
    
    for (int i = 1; i <= n; i++) scanf("%d", &ratio[i]);
    
    dijkstra(dist1, h1, 1);
    dijkstra(dist2, h2, n);

    multiset<LL> S;
    
    for (int i = 1; i <= n; i++)
    	// 节点可达才更新
        if (dist1[i] != INF && dist2[i] != INF) {
            // 上取整固定写法(a+b-1)/b
            S.insert(dist1[i] + (dist2[i] + ratio[i] - 1) / ratio[i]);
        }
    
    while (q--) {
        int x, a;
        scanf("%d%d", &x, &a);
        if (dist1[x] != INF && dist2[x] != INF) {
        	// 不能直接删,会把重复的全部删掉
            S.erase(S.find(dist1[x] + (dist2[x] + ratio[x] - 1) / ratio[x]));
            ratio[x] = a;
            S.insert(dist1[x] + (dist2[x] + ratio[x] - 1) / ratio[x]);
        }
        printf("%lld\n", *S.begin());
    }
    
    return 0;
}
参考资料

acwing.3468Y总

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/564826.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-06
下一篇 2022-04-06

发表评论

登录后才能评论

评论列表(0条)

保存