L3-1 森森旅游 (30 分)

题目链接

思路

这道题就是判断在哪个位置兑换旅游金能最省钱

  • 我们正向建图,跑一遍从1出发的使用现金的最短路
  • 我们建立反图,跑一遍从n出发的使用旅游金的最短路
  • 最后枚举每个点,set, 存下在这个点兑换旅游金的花费
  • 对于每一次利率调整,我们先删除这个点原先的花费,再存入现在的
  • 每一次询问,*set.begin() 就是答案

代码

#include<bits/stdc++.h>
#define ll long long
#define rep(i,x,y) for(int i=x; i<=y; ++i)
#define per(i,x,y) for(int i=x; i>=y; --i)
#define mem(a,b) memset(a,b,sizeof a)
#define pk push_back
#define PLI pair<ll,int>
using namespace std;
const int N = 2e5+9;;
int e[N],ne[N],h[N],idx,ma;
int w[N],a[N];
ll dis1[N],disn[N];
ll dis[N];
bool st[N];
void add(int a,int b,ll c) {
	e[idx]=b, ne[idx]=h[a],w[idx]=c ,h[a]=idx++;
}
struct Edge {
	int u,v,c,d;
} ed[N];
void Dijkstra(int s,int n) {

	rep(i,1,n) dis[i]=1e18;
	dis[s]=0;
	mem(st,false);
	priority_queue<PLI,vector<PLI> , greater<PLI> > q;
	q.push({0,s});
	while(q.size()) {
		PLI tmp = q.top();
		q.pop();
		ll d = tmp.first;
		int u = tmp.second;
		if(st[u]) continue;
		st[u]=true;
		for(int  i=h[u]; ~i; i=ne[i]) {
			int  j =e[i];
			if(dis[j]>dis[u]+1ll*w[i]) {
				dis[j]=dis[u]+w[i];
				q.push({dis[j], j});
			}
		}
	}
}
void init() {
	mem(h,-1);
	idx=0;
}
int main() {
	init();
	int n,m,q;
	cin>>n>>m>>q;
	rep(i,1,m) {
		int u,v,c,d;
		scanf("%d %d %d %d",&u,&v,&c,&d);
		ed[i]= {u,v,c,d};
		add(u,v,c);
	}
	rep(i,1,n) scanf("%d",a+i);
	Dijkstra(1,n);
	rep(i,1,n) {
		dis1[i]=dis[i];

	}

	init();
	rep(i,1,m) add(ed[i].v,ed[i].u,ed[i].d);
	Dijkstra(n,n);
	rep(i,1,n) disn[i]=dis[i];
	set<PLI> S;
	rep(i,1,n) {
		if(dis1[i]!=1e18&&disn[i]!=1e18) {
					ll t = disn[i]/a[i];
		if(disn[i]%a[i]) t++;
		S.insert({dis1[i]+t,i});
		}
	}
	while(q--) {
		int x,y;
		scanf("%d %d",&x,&y);
		if(dis1[x]!=1e18 && disn[x]!=1e18) {
			ll t = disn[x]/a[x]+dis1[x];
			if(disn[x]%a[x]) t++;
			S.erase({t,x});
			a[x]=y;
			t = disn[x]/a[x]+dis1[x];
			if(disn[x]%a[x]) t++;
			S.insert({t,x});
		}
		auto it = *S.begin();
		printf("%lld\n",it.first);
	}
	return 0;
}
/*
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


*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值