【CF】【Dijkstra】E. Buy and Delete
两个任务,一个是要跑出最短路,其二是在跑出最短路的时候,将所有边权进行一次汇总,要求在所有的最短路中,这生成的最短路的边权和是最小的。
设蓝球为起点,蓝球可以通过两条相等的路到达绿球,但为了使得总路径最小,要选择有经过蓝色边的这条路径。
为了方便比较我们可以开设一个cost数组用来记录某一个结点所转移过来的中的边中边权最小的边的边权,同时开一个pre数组去记录这个边的边号,方便后续答案的统计。
#include <bits/stdc++.h>
#define pii pair<ll,ll>
#define FI first
#define SE second
#define ll long long
#define de(x) cout<<" enter : "<<x<<endl;
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N = 3E5+100,M = 6E5+100;
ll h[N],ne[M],e[M],w[M],mark[M],idx;
void add(int u,int v,ll wei,int pos)
{
e[idx] = v,ne[idx] = h[u],w[idx] = wei,mark[idx] = idx/2+1,h[u] = idx++;
}
ll n,m,pre[N],used[N],dist[N],cost[N];
void dij(int u)
{
memset(dist,0x3f,sizeof(dist));
priority_queue<pii,vector<pii>,greater<pii>> heap;
dist[u] = 0;
heap.push({0,u});
while(heap.size())
{
pii t = heap.top();
heap.pop();
ll d = t.FI, u = t.SE;
if(used[u]) continue;
used[u] = true;
for(int i = h[u];~i;i=ne[i])
{
int v = e[i];
if(dist[v]>d+w[i])
{
dist[v] = d + w[i];
heap.push({dist[v],v});
cost[v] = w[i];
pre[v] = mark[i];
}
else if(dist[v]==d+w[i])
if(cost[v]>w[i])
{
cost[v] = w[i];
pre[v] = mark[i];
}
}
}
}
int main()
{
memset(h,-1,sizeof(h));
n = read(), m = read();
for(int i=1;i<=m;i++)
{
int u = read(), v = read(), wei = read();
add(u,v,wei,i);add(v,u,wei,i);
}
dij(read());
ll sum = 0;
for(int i=1;i<=n;i++)
sum += cost[i];
sort(pre+1,pre+1+n);
cout<<sum<<endl;
for(int i=2;i<=n;i++)
cout<<pre[i]<<" ";
return 0;
}