2023/3/12

L3-028

在这里插入图片描述
题意可知:从 1号城市 开始使用现金走到 k号城市 再从k号城市 开始使用旅游金走到 n号城市(1<=k<=n)
建立权值为c的正向边,求出从1跑到所有点的最短路
建立权值为d的反向边,求出从所有点跑到n的最短路
对于点k消耗的现金数量为 dis[1->k] + (dis[k->n]+a[k]-1)/a[k]
由于汇率a[i]会改变,所以可以使用线段树或者multiset去存储以1~n为转折点k时消耗的现金数量

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
typedef long long ll;
int n,m,k;
struct edge{
	int y,c,d;
	edge(int Y,int C,int D):y(Y),c(C),d(D){}
};
int inf;
vector<edge>z[100005],f[100005];
int zc[100005],fd[100005];
int res[100005];
bool vis[100005];
void bfs(){
	memset(zc,127,sizeof zc);
	memset(fd,127,sizeof fd);
	inf=zc[0];
	priority_queue<pair<int,int>>q;
	zc[1]=0;
	q.push({0,1});
	while(q.size()){
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		vis[x]=true;
		for(auto [y,c,d]:z[x]){
			if(zc[y]>zc[x]+c){
				zc[y]=zc[x]+c;
				q.push({-zc[y],y});
			}
		}
	}
	memset(vis,0,sizeof vis);
	fd[n]=0;
	q.push({0,n});
	while(q.size()){
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		vis[x]=true;
		for(auto [y,c,d]:f[x]){
			if(fd[y]>fd[x]+d){
				fd[y]=fd[x]+d;
				q.push({-fd[y],y});
			}
		}
	}
}
void slove(){
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++){
		int u,v,c,d;
		cin>>u>>v>>c>>d;
		if(u==v)continue;
		z[u].push_back(edge(v,c,d));
		f[v].push_back(edge(u,c,d));
	}
	bfs();
	multiset<int>s;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		if(fd[i]==inf)continue;
		res[i]=(fd[i]+x-1)/x+zc[i];
		s.insert(res[i]);
	}
	while(k--){
		int i,x;
		cin>>i>>x;
		if(fd[i]!=inf){
			s.erase(s.find(res[i]));
			res[i]=(fd[i]+x-1)/x+zc[i];
			s.insert(res[i]);
		}
		cout<<min(zc[n],*s.begin())<<endl;
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
//	cin>>T;
	while(T--){
		slove();
	}
	return 0;
}
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define mid ((l+r)>>1)
#define lt now<<1
#define rt now<<1|1
#define ltr lt,l,mid
#define rtr rt,mid+1,r
typedef long long ll;
int n,m,k;
struct edge{
	int y,c,d;
	edge(int Y,int C,int D):y(Y),c(C),d(D){}
};
int inf;
vector<edge>z[100005],f[100005];
int zc[100005],fd[100005];
int res[100005];
int tr[400005];
bool vis[100005];
void bfs(){
	memset(zc,127,sizeof zc);
	memset(fd,127,sizeof fd);
	inf=zc[0];
	priority_queue<pair<int,int>>q;
	zc[1]=0;
	q.push({0,1});
	while(q.size()){
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		vis[x]=true;
		for(auto [y,c,d]:z[x]){
			if(zc[y]>zc[x]+c){
				zc[y]=zc[x]+c;
				q.push({-zc[y],y});
			}
		}
	}
	memset(vis,0,sizeof vis);
	fd[n]=0;
	q.push({0,n});
	while(q.size()){
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		vis[x]=true;
		for(auto [y,c,d]:f[x]){
			if(fd[y]>fd[x]+d){
				fd[y]=fd[x]+d;
				q.push({-fd[y],y});
			}
		}
	}
}
void build(int now,int l,int r){
	if(l==r){
		tr[now]=res[l];
		return ;
	}
	build(ltr);
	build(rtr);
	tr[now]=min(tr[lt],tr[rt]);
}
void upd(int now,int l,int r,int i,int x){
	if(i==l&&i==r){
		tr[now]=x;
		return ;
	}
	if(i<=mid)upd(ltr,i,x);
	else upd(rtr,i,x);
	tr[now]=min(tr[lt],tr[rt]);
}
void slove(){
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++){
		int u,v,c,d;
		cin>>u>>v>>c>>d;
		if(u==v)continue;
		z[u].push_back(edge(v,c,d));
		f[v].push_back(edge(u,c,d));
	}
	bfs();
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		if(fd[i]!=inf)res[i]=(fd[i]+x-1)/x+zc[i];
		else res[i]=inf;
	}
	build(1,1,n);
	while(k--){
		int i,x;
		cin>>i>>x;
		if(fd[i]!=inf){
			res[i]=(fd[i]+x-1)/x+zc[i];
			upd(1,1,n,i,res[i]);
		}
		cout<<min(zc[n],tr[1])<<endl;
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	//	cin>>T;
	while(T--){
		slove();
	}
	return 0;
}

L3-029

在这里插入图片描述
虽然N很大但是M很小并且题目保证有唯一解,所以可以使用暴力dfs

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
int n,m;
vector<int>ans,h,a[105];
bool vis[105];
void dfs(int now){
	if(ans.size()==m){
		bool t=false;
		for(auto x:ans){
			if(t)cout<<" ";
			else t=true;
			cout<<x;
		}
		exit(0);
	}
	for(int i=0;i<m;i++){
		if(vis[i])continue;
		int j=0;
		for(auto x:a[i]){
			if(x!=h[now+j])break;
			j++;
		}
		if(j<a[i].size())continue;
		ans.push_back(i+1);
		vis[i]=true;
		dfs(now+a[i].size()-1);
		vis[i]=false;
		ans.pop_back();
	}
}
void slove(){
	cin>>n;
	h.assign(n,0);
	for(auto &x:h)cin>>x;
	cin>>m;
	for(int i=0;i<m;i++){
		int k;
		cin>>k;
		a[i].assign(k,0);
		for(auto &x:a[i])cin>>x;
	}
	dfs(0);
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
//	cin>>T;
	while(T--){
		slove();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值