Educational Codeforces Round 3:E (MST+树链剖分+RMQ)

首先跑一边kruskal,以MST的边建树。

若边在MST中则输出mincost

否则新加入的边将构成环,则需要去掉MST中u->v路径上的w最大边

询问也可用线段树,这里只需要维护最值,用RMQ编程复杂度低些(其实是懒

#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"vector"
#define ll long long

using namespace std;
const int MAXN = 200050;
const int MAXE = 400050;
const int INF = 0x3f3f3f3f;

int f[MAXN],first[MAXN],mark[MAXE],top[MAXN],dep[MAXN],faa[MAXN],siz[MAXN],son[MAXN],id[MAXN],val[MAXN];
ll dp[MAXN][20];
int n,m,tot,cnt;
ll cost,ans[MAXN];
struct nod{
    int u,v,w,o;
}E[MAXN];

bool cmp(nod a,nod b){
    return a.w<b.w;
}

struct node{
    int e,next;
    node(){}
    node(int a,int b):e(a),next(b){}
}edge[MAXN*2];

int fa(int x){
    return x==f[x]?x:f[x]=fa(f[x]);
}

void init(){
    tot=0;
    cost=0;
    cnt=-1;
    for(int i=1;i<=m;i++) f[i]=i;
    memset(first,-1,sizeof(first));
    memset(mark,0,sizeof(mark));
    memset(son,-1,sizeof(son));
}

void mer(int a,int b){
    a=fa(a);
    b=fa(b);
    f[a]=b;
}

void addedge(int u,int v){
    edge[tot]=node(v,first[u]);
    first[u]=tot++;
    edge[tot]=node(u,first[v]);
    first[v]=tot++;
}

void kruskal(){
    for(int i=0;i<m;i++){
        if(fa(E[i].u)!=fa(E[i].v)){
            mer(E[i].u,E[i].v);
            cost+=(ll)E[i].w;
            addedge(E[i].u,E[i].v);
            mark[i]=1;
        }
    }
}

void dfs1(int u,int pre,int depth){
    siz[u]=1;
    dep[u]=depth;
    faa[u]=pre;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(v==pre) continue;
        dfs1(v,u,depth+1);
        siz[u]+=siz[v];
        if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
    }
}

void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=cnt++;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(v==faa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}

int makermq(int N){
    for(int i=0;i<N;i++) dp[i][0]=val[i];
    for(int j=1;(1<<j)<=N;j++)
    for(int i=0;i+(1<<j)-1<N;i++) dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}

ll query(int l,int r){
    int k=(int)(log((r-l+1)*1.0)/log(2.0));
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}

ll findmax(int u,int v){
    int tu=top[u],tv=top[v];
    ll ans=-INF;
    while(tu!=tv){
        if(dep[tu]<dep[tv]){
            swap(tu,tv);
            swap(u,v);
        }
        ans=max(ans,query(id[tu],id[u]));
        u=faa[u];
        tu=top[u];
    }
    if(u==v) return ans;
    if(dep[u]>dep[v]) swap(u,v);
    return max(ans,query(id[son[u]],id[v]));
}

int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    init();
    for(int i=0;i<m;i++) {
        scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
        E[i].o=i;
    }
    sort(E,E+m,cmp);
    kruskal();
    dfs1(1,0,1);
    dfs2(1,1);
    for(int i=0;i<m;i++){
        if(!mark[i]) continue;
        if(dep[E[i].u]<dep[E[i].v]) swap(E[i].u,E[i].v);
        val[id[E[i].u]]=E[i].w;
    }
    makermq(n);
    for(int i=0;i<m;i++){
        if(mark[i]) ans[E[i].o]=cost;
        else{
            ll t=findmax(E[i].u,E[i].v);
            ans[E[i].o]=cost+(ll)(E[i].w-t);
        }
    }
    for(int i=0;i<m;i++) printf("%I64d
",ans[i]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/luxiaoming/p/5064986.html