#include <iostream>
#include <algorithm>
#include <queue>
#include <climits> //引入<climits>的类,注意如果引入<limits>会出现编译错误
#include <cstdio>
//#include <conio.h>
using namespace std;
typedef unsigned long long u64_T; //类型定义
const int MAXN = 50001; //定义结点个数
const u64_T INF=(u64_T)(1)<<63; //这种方法比较常用
//const u64_T INF = ULLONG_MAX; //定义unsigned long long 的最大值
struct edge_T {
int v;
u64_T w;
edge_T *next;
}*adj[MAXN], edges[2*MAXN]; //adj[i]存储以i为起点的邻接表的指针,memo[]存储所有的边
struct node_T { //用于优先级队列中记录节点的标号和最短路径
int v;
u64_T len;
bool operator < (const node_T &nod) const { //重载优先级队列的操作符,使其从小到大排列(注意格式必须完全一致)
return len > nod.len;
}
};
int edgenum; //记录边的总数
u64_T weight[MAXN];
int vn,en; //记录定点数和边数
u64_T dist[MAXN]; //存储结点的最小距离
void addEdge(int u, int v, u64_T w) {
edge_T *ptr = &edges[edgenum ++];
ptr -> v = v;
ptr -> w = w;
ptr -> next = adj[u]; //往前插入边
adj[u] = ptr;
}
void dijkstra(int s) { //n代表结点总数
priority_queue <node_T> Q; //使用优先级队列实现
node_T cur;
cur.v = s;
cur.len = 0;
Q.push(cur);
for(int i = 1; i <= vn; i ++) dist[i] = INF; //除源点以外的所有点的距离设置成无穷大(此处与邻接阵实现不同,临界阵赋值为到源点的距离,这里也可但是麻烦
dist[s] = 0;
while(! Q.empty()) {
int v = Q.top().v; //优先级队列使用top()
u64_T len = Q.top().len;
Q.pop();
if(d[v]!=len) continue;
for(edge_T *ptr = adj[v]; ptr; ptr = ptr -> next) {
int u = ptr -> v;
u64_T w = ptr -> w;
if(dist[v] + w < dist[u]) {
dist[u] = dist[v] + w;
cur.v = u;
cur.len = dist[u];
Q.push(cur);
}
}
}
}
int main() {
int i;
int src;
scanf("%d %d", &vn, &en);
for(i = 1; i <= vn; i ++) {
adj[i] = NULL; //初始化邻接表的指针
}
edgenum = 0; //初始化边数
int u, v;
u64_T w;
for(i = 1; i <= en; i ++) { //双向边
scanf("%d%d%I64u", &u, &v, &w); //最好采用此种读取方式,下边一种在某些题目中会出错
//scanf("%d%d%llu", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
src = 1;
dijkstra(src);
return 0;
}