(多校)歡樂豆
阿新 • • 發佈:2021-11-10
很新穎的題
首先觀察到 \(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); }