五道水题,但要手快才好。。。我手慢了,E题目都没看完TAT....
想了一发,很水,就是一遍Dijk即可,使用优先队列,同时记录由哪条边转移而来
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <vector> #define LL long long using namespace std; const int MAXN=300050; struct Edge{ int u,v,w,i,next; }edge[MAXN*2]; int weight[MAXN],head[MAXN],tot; int n,m; int chose[MAXN]; LL dis[MAXN]; bool vis[MAXN]; struct Node{ int u; LL d; Node(){} Node(int uu,LL dd){u=uu,d=dd;} bool operator<(const Node &a)const{ return d>a.d; } }; vector <int>ans; priority_queue<Node>pq; LL cur; void addedge(int u,int v,int w,int i){ edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].i=i; edge[tot].next=head[u]; head[u]=tot++; } void Dijk(int r){ cur=0; for(int i=1;i<=n;i++) dis[i]=1ll<<62; dis[r]=0; memset(chose,0,sizeof(chose)); memset(vis,false,sizeof(vis)); ans.clear(); pq.push(Node(r,0)); while(!pq.empty()){ Node tmp=pq.top(); pq.pop(); if(vis[tmp.u]) continue; if(tmp.u!=r){ cur+=weight[chose[tmp.u]]; ans.push_back(chose[tmp.u]); } LL d=tmp.d; vis[tmp.u]=true; for(int e=head[tmp.u];e!=-1;e=edge[e].next){ int v=edge[e].v; if(!vis[v]){ if(d+edge[e].w<dis[v]){ dis[v]=d+edge[e].w; chose[v]=edge[e].i; pq.push(Node(v,dis[v])); } else if(d+edge[e].w==dis[v]){ if(edge[e].w<weight[chose[v]]){ chose[v]=edge[e].i; } } } } } sort(ans.begin(),ans.end()); cout<<cur<<endl; int len=ans.size(); if(len>0){ printf("%d",ans[0]); for(int i=1;i<len;i++) printf(" %d",ans[i]); printf("\n"); } } int main(){ int u,v,w; while(scanf("%d%d",&n,&m)!=EOF){ memset(head,-1,sizeof(int)*(n+10)); tot=0; weight[0]=1e9+1000000; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w,i); addedge(v,u,w,i); weight[i]=w; } scanf("%d",&u); Dijk(u); } return 0; }