L. Campus
千万记得LL和更快的输入输出啊!!
题目链接:
正经题意:
无向图,t个时刻,求每个时刻的多源最短路
简而言之:
就是求多源最短路
思路:
如果每个时刻都求一次,那么时间复杂度是很高的,可以达到 O ( t ∗ n ∗ l o g ( m ) ) O(t*n*log(m)) O(t∗n∗log(m)),显然不可,注意看此题的k,很小,所以状态很少,不用重复计算,只需要对每个状态计算一次就够,最坏情况应该是层层包围吧,也只有30次
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+27;
int n,m,k,T;
LL a[N];
//int gate[N];
int get1[30];
int get2[30];
vector<pair<int,int> > ed[N];
LL dist[N];
int d[N];
int p[N];
int st[N];
map<int,int> mp;
int main(){
scanf("%d%d%d%d",&n,&m,&k,&T);
vector<pair<int,pair<int,int> > > tim;
for(int i = 1;i<=n;i++){
scanf("%lld",&a[i]);
}
int pp,l,r;
for(int i = 1;i<=k;i++){
scanf("%d%d%d",&pp,&l,&r);
tim.push_back({pp,{l,r}});
mp[pp] = i;//简单离散化一下
}
int u,v,w;
int kk = 0;
for(int i = 1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
ed[u].push_back({w,v});
ed[v].push_back({w,u});
}
LL sum = -1;
for(int t = 1;t <= T;t++){
memcpy(get1,get2,sizeof get2);//备份上次
memset(get2,0,sizeof get2);//初始化,准备记录本次的门
for(int i = 0;i<k;i++){
if(tim[i].second.first <= t && tim[i].second.second >= t){
int j = tim[i].first;
j = mp[j];
get2[j] = 1;
}
}
int flag = 0;
for(int i = 0;i<k;i++){
int j = tim[i].first;
j = mp[j];
if(get1[j] != get2[j]) flag = 1;
}
if(flag == 0){
printf("%lld\n",sum);//直接输出上次答案
continue;
}
priority_queue<pair<int,int> ,vector<pair<int,int> >,greater<pair<int,int> > >q;//小根堆
for(int i = 1;i<=n;i++){
dist[i] = 0x3f3f3f3f3f3f3f3f;
st[i] = 0;
}
for(int i = 0;i<k;i++){
if(tim[i].second.first <= t && tim[i].second.second >= t){
int j = tim[i].first;
dist[j] = 0;
q.push({0,j});//多源最短路
}
}
if(q.size() == 0){
sum = -1;
printf("%lld\n",sum);
continue;
}
while(q.size()){//Dijkstra
int x = q.top().second;
q.pop();
if(st[x]) continue;
st[x] = 1;
for(int i = 0;i<ed[x].size();i++){
int y = ed[x][i].second;
int c = ed[x][i].first;
if(c + dist[x] < dist[y]){
dist[y] = c + dist[x];
if(st[y]==0) q.push({c+dist[x],y});
}
}
}
sum = 0;
for(int i = 1;i<=n;i++){
if(dist[i] == 0x3f3f3f3f3f3f3f3f){
sum = -1;
break;
}
sum += (LL)a[i] * dist[i];
}
printf("%lld\n",sum);
}
return 0;
}