(多校)欢乐豆

很新颖的题

首先观察到 \(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);
}

posted @ 2021-11-10 20:09  zJx-Lm  阅读(86)  评论(0编辑  收藏  举报