[NOI2014]魔法森林

此题可以用spfa,也可以用LCT。
可spfa跑得比LCT快……

学习了一下怎么把边权变成点权:
新建一个点表示边,这个点的点权就是边权值
原来的点的权值为0(根据题目需要可以为其他值)
添加一条边时,连接两端的点
删除一条边时,需要找到这条边对应的点编号,两端删除

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node {
    int u,v,a,b;
    bool operator<(const node &res) const{
        return a<res.a;
    }
} edge[100005];
int FA[50005];
int val[150005],mx[150005],po[150005];
int ch[150005][2],fa[150005];
bool reversed[150005];
int sta[150005],top;
int n,m,ans=1e9;
inline int read() {
    char ch=0;int sum=0;
    while (ch>'9'||ch<'0') ch=getchar();
    while (ch>='0'&&ch<='9') sum=sum*10+ch-'0',ch=getchar();
    return sum;
}
int find(int x) {
    if (FA[x]!=x) FA[x]=find(FA[x]);
    return FA[x];
}
inline void Union(int x,int y) {
    FA[find(x)]=find(y);
}
inline void reverse(int x) {
    swap(ch[x][0],ch[x][1]);
    reversed[x]^=1;
}
inline void pushdown(int x) {
    if (reversed[x]) {
        if (ch[x][0]) reverse(ch[x][0]);
        if (ch[x][1]) reverse(ch[x][1]);
        reversed[x]=0;
    }
}
inline void pushup(int x) {
    int pp=x,tmp=val[x];
    if (mx[ch[x][1]]>tmp) pp=po[ch[x][1]],tmp=mx[ch[x][1]];
    if (mx[ch[x][0]]>tmp) pp=po[ch[x][0]],tmp=mx[ch[x][0]];
    po[x]=pp;mx[x]=tmp;
}
inline bool notroot(int x) {
    return (ch[fa[x]][0]==x)||(ch[fa[x]][1]==x);
}
inline void rotate(int x) {
    int fa1=fa[x],fa2=fa[fa1],side=(ch[fa1][1]==x),c=ch[x][side^1];
    fa[x]=fa2;if (notroot(fa1)) ch[fa2][ch[fa2][1]==fa1]=x;
    ch[fa1][side]=c;if (c) fa[c]=fa1;
    fa[fa1]=x;ch[x][side^1]=fa1;
    pushup(fa1);pushup(x);
}
inline void splay(int x) {
    int u=x,top=0;
    while (notroot(u)) sta[++top]=u,u=fa[u];
    sta[++top]=u;
    while (top) pushdown(sta[top--]);
    while (notroot(x)) {
        int fa1=fa[x],fa2=fa[fa1];
        if (notroot(fa1)) {
            if ((ch[fa2][0]==fa1)^(ch[fa1][0]==x)) rotate(x);
            else rotate(fa1);
        }
        rotate(x);
    }
}
inline void access(int x) {
    int u=0;
    while (x!=0) {
        splay(x);
        ch[x][1]=u;
        pushup(x);
        u=x;
        x=fa[x];
    }
}
inline void makeroot(int x) {
    access(x);splay(x);
    reverse(x);
}
inline int findroot(int x) {
    access(x);splay(x);
    while (ch[x][0]) pushdown(x),x=ch[x][0];
    splay(x);
    return x;
}
inline void split(int x,int y) {
    makeroot(x);
    access(y);splay(y);
}
inline void link(int x,int y) {
    makeroot(x);
    if (findroot(y)!=x) fa[x]=y;
}
inline void cut(int x,int y) {
    makeroot(x);
    if (findroot(y)==x && fa[y]==x && ch[x][1]!=0) {
        fa[y]=ch[x][0]=0;
        pushup(x);
    }
}
inline void addedge(int i) {
    int u=edge[i].u,v=edge[i].v;
    if (find(u)!=find(v)) {
        Union(u,v);
        val[i+n]=mx[i+n]=edge[i].b;
        po[i+n]=i+n;
        link(u,i+n);
        link(v,i+n);
    }
    else {
        split(u,v);
        if (edge[i].b<mx[v]) {
            int w=po[v];
            cut(w,edge[w-n].u);
            cut(w,edge[w-n].v);
            val[i+n]=mx[i+n]=edge[i].b;
            po[i+n]=i+n;
            link(u,i+n);
            link(v,i+n);
        }
    }
}
int main() {
    n=read(),m=read();
    for (int i=1;i<=m;i++) {
        edge[i].u=read();edge[i].v=read();
        edge[i].a=read();edge[i].b=read();
    }
    sort(edge+1,edge+m+1);
    for (int i=1;i<=n;i++) FA[i]=po[i]=i;
    for (int i=1;i<=m;i++) {
        addedge(i);
        while (i<m && edge[i].a==edge[i+1].a) addedge(++i);
        if (find(1)==find(n)) {
            split(1,n);
            ans=min(ans,edge[i].a+mx[n]);
        }
    }
    if (ans==1e9) puts("-1");
    else printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014304190/article/details/80502233