D.tokitsukaze and Event
链接:https://ac.nowcoder.com/acm/contest/1080/D
来源:牛客网
题目描述
这天,tokitsukaze带着她的舰队去才归一儿海探索。这个海域有n个站点,深海舰队控制着这片海域的m条航线,这些航线连接着这n个点,第i条航线连接着ui,vi两个点。航线都是正确的,也就是说没有重复的航线,也没有任何一个点与自己相连。tokitsukaze的舰队经过第i条航线时,会受到来自深海舰队的ai点伤害。
tokitsukaze可以在某个休息站点将接下来的战斗切换至夜战模式,这样在她的舰队经过第i条航线时,受到的伤害就变为bi,不过一旦切换到夜战模式就不能再次切换回来,所以她必须考虑清楚在哪里切换。
现在有个限时活动。活动难度分为1,2,3,4,…n,在难度1下,tokitsukaze可以在任意站点切换到夜战模式,而在难度2下,不能在站点1切换到夜战模式,在难度3下,不能在站点1,2切换模式…以此类推,即在难度k下,tokitsukaze不能在站点1,2,3,4,5…k-1切换模式。同时,活动还要求在游戏结束时必须处于夜战模式。
现在tokitsukaze的舰队从s点出发,要前往深海大本营所在的t点。请你告诉她,在难度为1,2,3,4,5…n时,她的舰队结束游戏时受到的最小伤害。
输入描述:
第一行包括2个正整数n,m,(2≤n≤105,1≤m≤min(n*(n-1)/2,105))。
接下来m行,每行包括4个正整数u,v,a,b,(1≤u,v≤n,1≤a,b≤109)。
最后一行包括2个正整数s,t,(1≤s,t≤n)。
输出描述:
请你告诉tokitsukaze,在难度为1,2,3,4,5…n时,她的舰队处于夜战模式结束游戏受到的最小伤害。
示例1
输入
4 3
1 4 1 30
1 2 1 10
1 3 20 1
2 3
输出
2
11
21
33
示例2
输入
4 3
1 4 30 1
1 2 10 1
1 3 20 1
3 1
输出
1
1
1
51
分析:
假设切换的点编号为x,起点为s,终点为t
显然最小伤害为s到x的白天模式最短距离+x到t的黑夜模式最短距离
最短距离很容易就能想到最短路算法
以s为起点,边权为白天模式的伤害值跑一遍最短路,最短距离存到d1[]
以t为起点,边权为黑夜模式的伤害值跑一遍最短路,最短距离存到d2[]
在x点切换的最小伤害为d1[x]+d2[x]
题目说难度k下,1-(k-1)不能切换,则只有k和k之后的点可以切换,
那么答案就是k点以及k点之后的d1[x]+d2[x]最小值
从后往前跑一边后缀min,最后依次输出就行了
还有一个坑点就是数据是1e9级别的,一些涉及加法的数组要用long long
ps:
这题我自己刚开始写的时候直接写了两个前向星建两个模式的图。
然后看了别人代码发现一个前向星存两个边权就行了(我太菜了)。
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxm=1e5+5;
const ll inf=(1LL<<60);
int head[maxm],nt[maxm<<1],to[maxm<<1],w1[maxm<<1],w2[maxm<<1],cnt;//w1,w2存两个模式的边权
ll d1[maxm],d2[maxm];
int mark[maxm];
int n,m,s,t;
ll sum[maxm];
void init(){
memset(head,-1,sizeof head);
for(int i=0;i<maxm;i++)d1[i]=d2[i]=inf;//设为inf
cnt=1;
}
void add(int x,int y,int w,int ww){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w1[cnt]=w,w2[cnt]=ww;
}
void spfa(int st,int *w,ll *d){
memset(mark,0,sizeof mark);
queue<int>q;
q.push(st);
mark[st]=1;
d[st]=0;
while(!q.empty()){
int x=q.front();
q.pop();
mark[x]=0;
for(int i=head[x];i!=-1;i=nt[i]){
int v=to[i];
if(d[v]>d[x]+w[i]){
d[v]=d[x]+w[i];
if(!mark[v]){
mark[v]=1;
q.push(v);
}
}
}
}
}
int main(){
init();
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c,d;
cin>>a>>b>>c>>d;
add(a,b,c,d);
add(b,a,c,d);
}
cin>>s>>t;
spfa(s,w1,d1);
spfa(t,w2,d2);
sum[n]=d1[n]+d2[n];
for(int i=n-1;i>=1;i--){
sum[i]=min(sum[i+1],d1[i]+d2[i]);
}
for(int i=1;i<=n;i++){
cout<<sum[i]<<endl;
}
return 0;
}