[NOI2014]魔法森林

Description:

给定一个无向连通图,每条边有两个属性,(a_i,b_i),找一条从1号点到n号点的路径,使路径上的 ({max}a_{i}+maxb_{i}) 最小

Hint:

(n=5*10^4,m<=10^5)

Solution:

一看到题目就想到最短路,然后发现行不通

最短路行不通,那就考虑最小生成树

一个属性显然可以直接做

但是现在有两个属性

考虑按边权枚举其中一个属性

即按 (ai) 排序后每次向图中加入一条边

同时维护以 (bi) 为边权的最小生成树

若成环,选择一条 (bi) 较小的边

每次加边后更新1到n的答案

维护最小生成树用 (lct) 解决

#include<bits/stdc++.h>
using namespace std;
const int mxn=1e6+5,inf=1e9;
struct ed {
    int u,v,w,z,id;
}q[mxn];
int n,m,tot,mx[mxn],fa[mxn],ch[mxn][2],rev[mxn],st[mxn],val[mxn];
pair<int ,int > g[mxn];
map<pair<int ,int >,int > s;

int cmp(ed x,ed y) {
    return x.w<y.w;
}

inline void checkmi(int &x,int y,int z) {
    if(x>y+z) x=y+z;
}

namespace lct {
    int isnotrt(int x) {
        return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
    }
    void push_up(int x) {
        mx[x]=x;
        if(val[mx[x]]<val[mx[ch[x][0]]]) mx[x]=mx[ch[x][0]];
        if(val[mx[x]]<val[mx[ch[x][1]]]) mx[x]=mx[ch[x][1]];
    }
    void push_down(int x) {
        if(rev[x]) {
            swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
            swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
            rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; rev[x]=0;
        }
    }
    void rotate(int x) {
        int y=fa[x],z=fa[y],tp=ch[y][1]==x;
        if(isnotrt(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;
        ch[y][tp]=ch[x][tp^1],fa[ch[x][tp^1]]=y;
        ch[x][tp^1]=y; fa[y]=x;
        push_up(y),push_up(x);
    }
    void splay(int x) {
        int tp=x,s=0; st[++s]=tp;
        while(isnotrt(tp)) st[++s]=tp=fa[tp];
        while(s) push_down(st[s]),--s;
        while(isnotrt(x)) {
            int y=fa[x],z=fa[y];
            if(isnotrt(y)) 
                (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
            rotate(x);
        }
    }
    void access(int x) {
        for(int y=0;x;x=fa[y=x]) 
            splay(x),ch[x][1]=y,push_up(x);
    }
    void makert(int x) {
        access(x); splay(x);
        swap(ch[x][0],ch[x][1]); rev[x]^=1; 
    }
    int findrt(int x) {
        access(x); splay(x);
        while(ch[x][0]) push_down(x),x=ch[x][0];
        splay(x); return x;
    }
    void link(int x,int y) {
        makert(x); fa[x]=y;
    }
    void cut(int x,int y) {
        makert(x); access(y); splay(y);
        fa[x]=ch[y][0]=0; push_up(y);//
    }
    int query(int x,int y) {
        makert(x); access(y); splay(y);
        return mx[y];
    }
}
using namespace lct;

int main()
{
    scanf("%d%d",&n,&m); tot=n; int ans=inf;
    for(int i=1;i<=m;++i) {
        scanf("%d%d%d%d",&q[i].u,&q[i].v,&q[i].w,&q[i].z);
        s[make_pair(q[i].u,q[i].v)]=s[make_pair(q[i].v,q[i].u)]=++tot;
        val[tot]=q[i].z; g[tot]=make_pair(q[i].u,q[i].v);
    }
    sort(q+1,q+m+1,cmp);
    for(int i=1;i<=m;++i) {
        int u=q[i].u,v=q[i].v,w=s[make_pair(u,v)];
        if(findrt(u)!=findrt(v)) 
            link(u,w),link(w,v),mx[w]=w,val[w]=q[i].z;
        else {
            int tp=query(u,v); 
            if(val[tp]>q[i].z) {
                cut(g[tp].first,tp);
                cut(g[tp].second,tp);
                link(u,w); link(v,w);
                mx[w]=w,val[w]=q[i].z; 
            }
        }
        if(findrt(1)==findrt(n)) checkmi(ans,val[query(1,n)],q[i].w);
    }
    printf("%d",ans==inf?-1:ans);
}
原文地址:https://www.cnblogs.com/list1/p/10398164.html