#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const ll mod=1000000007;
const int max_n=10005;
const int max_p=100005;
int par[max_n];//根结点
int n, p;//牧场数(结点),道路数(边)
int c[max_n];//谈话时间
struct edge {
int from, to, cost;//起点,终点,边权
}e[max_p];
int cmp(edge x, edge y) {
return x.cost<y.cost;
}
//初始化根结点为该结点本身
void init() {
for(int i=1; i<=n; i++) {
par[i]=i;
}
}
//查找根结点
int fid(int x) {
if(par[x]==x) return x;
else return par[x]=fid(par[x]);
}
//合并两集合
void unite(int x, int y) {
par[y]=par[x];
}
//最小生成树
int kruskal() {
sort(e, e+p, cmp);//把边按权值从小到大排序
int cnt=0;//构建的最小生成树加入的边数
int ans=0;//最小生成树的边权总和
for(int i=0; i<p; i++) {
if(cnt==n-1) break;//已构建好最小生成树
int a=fid(e[i].from);
int b=fid(e[i].to);
if(a!=b) {
unite(a, b);
ans+=e[i].cost;
cnt++;
}
}
return ans;
}
int main() {
int minc=1005;//最小谈话时间
int u, v, w;
cin>>n>>p;
for(int i=1; i<=n; i++) {
scanf("%d", &c[i]);
minc=min(minc, c[i]);
}
for(int i=0; i<p; i++) {
scanf("%d %d %d", &u, &v, &w);
e[i].from=u;
e[i].to=v;
e[i].cost=w*2+c[u]+c[v];
}
init();
int ans=minc+kruskal();
printf("%d\n", ans);
return 0;
}