• 团体程序设计天梯赛 L3028 森森旅游(29分代码)


    不知道为什么一个一分的点死活过不去。。。

    L3-028 森森旅游 (30 分)

    好久没出去旅游啦!森森决定去 Z 省旅游一下。

    Z 省有 n 座城市(从 1 到 n 编号)以及 m 条连接两座城市的有向旅行线路(例如自驾、长途汽车、火车、飞机、轮船等),每次经过一条旅行线路时都需要支付该线路的费用(但这个收费标准可能不止一种,例如车票跟机票一般不是一个价格)。

    Z 省为了鼓励大家在省内多逛逛,推出了旅游金计划:在 i 号城市可以用 1 元现金兑换 a**i 元旅游金(只要现金足够,可以无限次兑换)。城市间的交通即可以使用现金支付路费,也可以用旅游金支付。具体来说,当通过第 j 条旅行线路时,可以用 c**j 元现金 d**j 元旅游金支付路费。注意: 每次只能选择一种支付方式,不可同时使用现金和旅游金混合支付。但对于不同的线路,旅客可以自由选择不同的支付方式。

    森森决定从 1 号城市出发,到 n 号城市去。他打算在出发前准备一些现金,并在途中的某个城市将剩余现金 全部 换成旅游金后继续旅游,直到到达 n 号城市为止。当然,他也可以选择在 1 号城市就兑换旅游金,或全部使用现金完成旅程。

    Z 省政府会根据每个城市参与活动的情况调整汇率(即调整在某个城市 1 元现金能换多少旅游金)。现在你需要帮助森森计算一下,在每次调整之后最少需要携带多少现金才能完成他的旅程。

    输入格式:

    输入在第一行给出三个整数 nmq(1≤n≤105,1≤m≤2×105,1≤q≤105),依次表示城市的数量、旅行线路的数量以及汇率调整的次数。

    接下来 m 行,每行给出四个整数 uvcd(1≤u,vn,1≤c,d≤109),表示一条从 u 号城市通向 v 号城市的有向旅行线路。每次通过该线路需要支付 c 元现金或 d 元旅游金。数字间以空格分隔。输入保证从 1 号城市出发,一定可以通过若干条线路到达 n 号城市,但两城市间的旅行线路可能不止一条,对应不同的收费标准;也允许在城市内部游玩(即 uv 相同)。

    接下来的一行输入 n 个整数 a1,a2,⋯,a**n(1≤a**i≤109),其中 a**i 表示一开始在 i 号城市能用 1 元现金兑换 a**i 个旅游金。数字间以空格分隔。

    接下来 q 行描述汇率的调整。第 i 行输入两个整数 x**ia**i′(1≤x**in,1≤a**i′≤109),表示第 i 次汇率调整后,x**i 号城市能用 1 元现金兑换 a**i′ 个旅游金,而其它城市旅游金汇率不变。请注意:每次汇率调整都是在上一次汇率调整的基础上进行的。

    输出格式:

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

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

    输入样例:

    6 11 3
    1 2 3 5
    1 3 8 4
    2 4 4 6
    3 1 8 6
    1 3 10 8
    2 3 2 8
    3 4 5 3
    3 5 10 7
    3 3 2 3
    4 6 10 12
    5 6 10 6
    3 4 5 2 5 100
    1 2
    2 1
    1 17
    

    输出样例:

    8
    8
    1
    

    样例解释:

    对于第一次汇率调整,森森可以沿着 1→2→4→6 的线路旅行,并在 2 号城市兑换旅游金;

    对于第二次汇率调整,森森可以沿着 1→2→3→4→6 的线路旅行,并在 3 号城市兑换旅游金;

    对于第三次汇率调整,森森可以沿着 1→3→5→6 的线路旅行,并在 1 号城市兑换旅游金。

    双向最短路,原图对现金跑1为起点的最短路,建反图对旅游金跑n为起点的最短路,得到每个点到n需要花费的现金和准备金,进而算出到终点的现金。这里实际上可以用multiset存最终花费的现金,因为只关心结果,所以修改的时候直接取出一个值相等的删掉,然后把新值插进去。我写的是线段树维护每个点的汇率以及花费的现金的最大值,实现单点修改和区间查询1到n的最大值即可。

    #include <bits/stdc++.h>
    #define N 100005
    #define M 200005
    #define int long long
    using namespace std;
    int n, m, Q;
    int head[N], ver[2 * M], Next[2 * M], c[2 * M], tot = 0;
    int head2[N], ver2[2 * M], Next2[2 * M], d[2 * M], tot2 = 0;
    int d1[N], d2[N];
    bool vis[N];
    void add(int x, int y, int z) {
    	ver[++tot] = y, c[tot] = z, Next[tot] = head[x], head[x] = tot;
    }
    void add2(int x, int y, int w) {
    	ver2[++tot2] = y, d[tot2] = w, Next2[tot2] = head2[x], head2[x] = tot2;
    }
    priority_queue<pair<int, int> > q;
    void dij1() {
    	for(int i = 1; i <= n; i++) d1[i] = 1e18;
    	memset(vis, 0, sizeof(vis));
    	d1[1] = 0;
    	q.push(make_pair(0, 1));
    	while(q.size()) {
    		int x = q.top().second;
    		q.pop();
    		if(vis[x]) continue;
    		vis[x] = 1;
    		for(int i = head[x]; i; i = Next[i]) {
    			int y = ver[i], z = c[i];
    			if(d1[y] > d1[x] + z) {
    				d1[y] = d1[x] + z;
    				q.push(make_pair(-d1[y], y));
    			}
    		}
    	}
    }
    void dij2() {
    	for(int i = 1; i <= n; i++) d2[i] = 1e18;
    	memset(vis, 0, sizeof(vis));
    	d2[n] = 0;
    	while(q.size()) q.pop();
    	q.push(make_pair(0, n));
    	while(q.size()) {
    		int x = q.top().second;
    		q.pop();
    		if(vis[x]) continue;
    		vis[x] = 1;
    		for(int i = head2[x]; i; i = Next2[i]) {
    			int y = ver2[i], z = d[i];
    			if(d2[y] > d2[x] + z) {
    				d2[y] = d2[x] + z;
    				q.push(make_pair(-d2[y], y));
    			}
    		}
    	}
    }
    struct node {
    	int id;
    	int a;//汇率
    	int cash;
    	int travel;
    } nd[N];
    struct SegmentTree {
    	int p, l, r, dat, cash, a, travel;
    } t[N * 4];
    void build(int p, int l, int r) {
    	if(l == r) {
    		t[p].l = l, t[p].r = r, t[p].dat = (nd[l].cash + (long long) ceil(nd[l].travel * 1.0 / nd[l].a)),
    		t[p].cash = nd[l].cash, t[p].travel = nd[l].travel;
    		return; 
    	}
    	int mid = (l + r) >> 1;
    	build(2 * p, l, mid);
    	build(2 * p + 1, mid + 1, r);
    	t[p].dat = min(t[2 * p].dat, t[2 * p + 1].dat);
    }
    int query() {
    	return t[1].dat;
    }
    void modify(int p ,int l, int r, int x, int val) {
    	if(l == r) {
    		t[p].a = val;
    		t[p].dat = (t[p].cash + (long long) ceil(t[p].travel * 1.0 / t[p].a));
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid) modify(2 * p, l, mid, x, val);
    	else modify(2 * p + 1, mid + 1, r, x, val);
    	t[p].dat = min(t[2 * p].dat, t[2 * p + 1].dat);
    }
    signed main() {
    	cin >> n >> m >> Q;
    	for(int i = 1; i <= m; i++) {
    		int x, y, z, w;
    		cin >> x >> y >> z >> w;
    		add(x, y, z);
    		add2(y, x, w);
    
    	}
    	dij1();
    	dij2();
    	for(int i = 1; i <= n; i++) {
    		int aa;
    		cin >> aa;
    		nd[i] = {i, aa, d1[i], d2[i]};
    	}
    	build(1, 1, n);
    	while(Q--) {
    		int xi, ai;
    		cin >> xi >> ai;
    		if(n == 1) {
    			puts("0");
    			continue;
    		}
    		modify(1, 1, n, xi, ai);
    		cout << query() << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    python的多线程问题
    python 调用函数时使用星号 *, **
    python正则中的贪婪与非贪婪
    python中文处理
    Python 模块之 ConfigParser: 用 Python 解析配置文件
    substr使用注意
    [转]互联网后台服务的协议设计
    Java设计模式从精通到入门四 工厂方法模式
    logback中logger详解
    logback实践笔记
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/16149766.html
Copyright © 2020-2023  润新知