(多校)欢乐豆
很新颖的题
首先观察到 \(m\) 很小,考虑从其入手
如果我们把 \(m\) 个边看做双向边,把连在一起的点看为联通块
那么一个联通块内的点的个数是和 \(m\) 同级的
我们可以对于每个联通块做一遍全源最短路
对于一个联通块内的点对 \((i,j)\)
分情况考虑:
首先如果 \((i,j)\) 有连边,可以直接到,更新一遍答案
其次 \(i\) 点也可以先到联通块外的点,再回到 \(j\) 点
跑最短路时,对于 \(i\) 点的所有出边所对应的点\(y\) ,我们将其排序
接下来,我们实际要做的就是单点修改和区间修改,即对于每一个 \([y_i,y_{i+1}]\) 区间更新 \(dis\)
下一个转移点即为线段树中最小值所在位置
每次转移完把该点打上删除标记即可
Code
#include <bits/stdc++.h>
#define re register
#define int long long
// #define ll long long
#define pir make_pair
#define fr first
#define sc second
#define db double
#define pb push_back
using namespace std;
const int mol=998244353;
const int maxn=2e5+10;
const int INF=1e9+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read() {
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
int n,m,w[maxn],size[maxn],tot,id[maxn],eid[maxn]; int ans,dis[maxn];
int tos; struct DATE { int a,b; } que[maxn];
int fa[maxn]; bool vs[maxn];
inline int find(int x) { return x==fa[x]? x:fa[x]=find(fa[x]); }
map<pair<int,int>,int> vis;
vector<pair<int,int> > vec;
vector<int> scc[maxn];
multiset<int> ss; int as;
struct EDGE { int var,nxt,cst; } edge[maxn<<1];
int head[maxn],cnt;
inline void add(int a,int b,int c) { edge[++cnt]=(EDGE){ b,head[a],c }; head[a]=cnt; }
namespace STG {
#define lid (id<<1)
#define rid (id<<1|1)
struct TREE { int pos,minl,lazy; } tre[maxn<<2];
inline void update(int id) {
if(tre[lid].minl==tre[rid].minl&&tre[lid].minl==-1) { tre[id].minl=-1; return ; }
if(tre[lid].minl==-1||(tre[lid].minl>tre[rid].minl&&tre[rid].minl!=-1)) {
tre[id].minl=tre[rid].minl;
tre[id].pos=tre[rid].pos;
}
else {
tre[id].minl=tre[lid].minl;
tre[id].pos=tre[lid].pos;
}
}
inline void build(int id,int l,int r) {
tre[id].minl=tre[id].lazy=INF;
if(l==r) { tre[id].pos=eid[l]; return ; }
int mid=(l+r)>>1;
build(lid,l,mid); build(rid,mid+1,r);
update(id);
}
inline void push_down(int id) {
int s=tre[id].lazy; tre[id].lazy=INF;
tre[lid].minl=min(s,tre[lid].minl);
tre[lid].lazy=min(s,tre[lid].lazy);
tre[rid].minl=min(s,tre[rid].minl);
tre[rid].lazy=min(s,tre[rid].lazy);
}
inline void ins(int id,int l,int r,int ll,int rr,int val) {
if(ll<=l&&r<=rr) { tre[id].minl=min(tre[id].minl,val); tre[id].lazy=min(tre[id].lazy,val); return ; }
int mid=(l+r)>>1;
if(tre[id].lazy!=INF) push_down(id);
if(ll<=mid) ins(lid,l,mid,ll,rr,val);
if(rr>mid) ins(rid,mid+1,r,ll,rr,val);
update(id);
}
inline int quy(int id,int l,int r,int pos) {
if(l==r) return tre[id].minl;
if(tre[id].lazy!=INF) push_down(id);
int mid=(l+r)>>1;
if(pos<=mid) return quy(lid,l,mid,pos);
else return quy(rid,mid+1,r,pos);
}
}
inline void spfa(int s) {
STG::ins(1,1,tot,id[s],id[s],0);
while(STG::tre[1].minl!=-1) {
int now=STG::tre[1].pos;
int ds=STG::tre[1].minl; dis[now]=ds;
tos=0;
for(re int i=head[now];i;i=edge[i].nxt) que[++tos]=(DATE){ edge[i].var,edge[i].cst } ;
sort(que+1,que+1+tos,[](DATE x,DATE y) { return id[x.a]<id[y.a]; });
int las=0;
for(re int i=1,asd;i<=tos;i++) {
int a=que[i].a,oi=ds+min(que[i].b,w[now]+as);
if(las+1<=id[a]-1) { STG::ins(1,1,tot,las+1,id[a]-1,ds+w[now]); }
las=id[a];
if((asd=STG::quy(1,1,tot,id[a]))>oi) { STG::ins(1,1,tot,id[a],id[a],oi); }
}
if(las+1<=tot) STG::ins(1,1,tot,las+1,tot,ds+w[now]);
STG::ins(1,1,tot,id[now],id[now],-1);
}
}
inline void wor(int rt) {
for(re int i=0;i<scc[rt].size();i++) { ss.erase(ss.find(w[scc[rt][i]])); }
if(ss.size()!=0) as=*ss.begin(); else as=INF;
tot=0;
for(re int j=0;j<scc[rt].size();j++) { id[scc[rt][j]]=++tot,eid[tot]=scc[rt][j]; }
for(re int i=0;i<scc[rt].size();i++) {
STG::build(1,1,tot);
spfa(scc[rt][i]);
for(re int j=0;j<scc[rt].size();j++) ans+=dis[scc[rt][j]];
int ks=w[scc[rt][i]];
for(re int j=0;j<scc[rt].size();j++) {
ks=min(ks,dis[scc[rt][j]]+w[scc[rt][j]]);
}
ans+=(n-scc[rt].size())*ks;
}
for(re int i=0;i<scc[rt].size();i++) ss.insert(w[scc[rt][i]]);
}
signed main(void) {
freopen("happybean.in","r",stdin); freopen("happybean.out","w",stdout);
n=read(); m=read();
for(re int i=1;i<=n;i++) { w[i]=read(); size[i]=1; ss.insert(w[i]); fa[i]=i; }
for(re int i=1,a,b,c,ls;i<=m;i++) {
a=read(); b=read(); c=read(); if(find(a)!=find(b)) { fa[find(a)]=find(b); }
if(!vis[pir(a,b)]) { vec.pb(pir(a,b)); }
vis[pir(a,b)]=c;
}
for(re int i=0;i<vec.size();i++) { add(vec[i].fr,vec[i].sc,vis[pir(vec[i].fr,vec[i].sc)]); }
for(re int i=1;i<=n;i++) { scc[find(i)].pb(i); }
for(re int i=1;i<=n;i++) {
if(scc[find(i)].size()==1) { ans+=(n-1)*w[i]; }
else if(find(i)==i) wor(find(i));
}
printf("%lld\n",ans);
}