洛谷2387 BZOJ3669魔法森林题解

题目链接

BZ链接

这道题被很多人用spfa水了过去,表示很。。。

其实spfa很好卡,这组数据可以卡掉大多数spfa

链接:密码:rjvk

这里讲一下LCT的做法

我们按照a将边排序,然后依次添加

每次加入时若两边没有联通,就直接加入,否则就

检查两边的路径中权值b最大的权值是多少,如果大于当前加入边的权值

就将该边删掉,然后将当前边加入

注意lct维护边权时需要用到拆点

# include<iostream>
# include<algorithm>
# include<cmath>
# include<cstring>
# include<cstdio>
using namespace std;
const int mn = 150005;
const int inf = 2147483647;
struct edge{int u,v,a,b;};
edge e[mn];
bool cmp(const edge &x,const edge &y)
{
    if(x.a==y.a) return x.b<y.b;
    else return x.a<y.a;
}
int n,m,ans,fa[mn];
int _find(int x) {return x==fa[x] ? x : fa[x]=_find(fa[x]);}
struct LCT{
    int val[mn],fa[mn],c[mn][2],mx[mn],st[mn];
    //mx[x]表示子树中权值最大的点的编号
    bool rev[mn];
    bool nroot(int x)
    {
        return c[fa[x]][0]==x || c[fa[x]][1]==x;
    }
    void zhuan(int x)
    {
        swap(c[x][1],c[x][0]);
        rev[x]^=1;
    }
    void pushdown(int x)
    {
        if(rev[x])
        {
            rev[x]=0;
            if(c[x][0]) zhuan(c[x][0]);
            if(c[x][1]) zhuan(c[x][1]);
        }
    }
    void updown(int x)
    {
        mx[x]=x;
        if(c[x][0])
        {
            if(val[mx[c[x][0]]]>val[mx[x]])
               mx[x]=mx[c[x][0]];
        }
        if(c[x][1])
        {
            if(val[mx[c[x][1]]]>val[mx[x]])
               mx[x]=mx[c[x][1]];
        }
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],flag;
        if(c[y][0]==x) flag=1;
        else flag=0;
        if(nroot(y))
        {
            if(c[z][0]==y) c[z][0]=x;
            else c[z][1]=x;
        }
        c[y][flag^1]=c[x][flag],fa[c[x][flag]]=y;
        c[x][flag]=y;
        fa[y]=x,fa[x]=z;
        updown(y);
        updown(x);
    }
    void splay(int x)
    {
        int top=0;
        st[++top]=x;
        for(int i=x;nroot(i);i=fa[i])
           st[++top]=fa[i];
        for(;top;top--) pushdown(st[top]);
        while(nroot(x))
        {
            int y=fa[x],z=fa[y];
            if(nroot(y))
            {
                if((c[y][0]==x) ^ (c[z][0]==y))
                  rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
        updown(x);
    }
    void access(int x)
    {
       int t=0;
       while(x){splay(x);c[x][1]=t;updown(x);t=x;x=fa[x];}
    }
    void makeroot(int x)
    {
        access(x);
        splay(x);
        zhuan(x);
    }
    void link(int x,int y)
    {
        makeroot(x);
        fa[x]=y;
    }
    void cut(int x,int y)
    {
        makeroot(x);
        access(y);
        splay(y);
        c[y][0]=fa[x]=0;
        updown(y);
    }
    int query(int x,int y)
    {
        makeroot(x);
        access(y);
        splay(y);
        return mx[y];
    }
}T;
void pre()
{
    for(int i=1;i<=n;i++)
      fa[i]=i;
    for(int i=1;i<=m;i++)
      T.val[i+n]=e[i].b;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
       scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].a,&e[i].b);
    sort(e+1,e+1+m,cmp);
    ans=inf;
    pre();
   /* for(int i=1;i<=m;i++)
    printf("%d %d\n",e[i].a,e[i].b);*/
    for(int i=1;i<=m;i++)
    {
        int x=e[i].u,y=e[i].v;
        int xx=_find(x),yy=_find(y);
        if(xx!=yy)
        {
            fa[xx]=yy;
            T.link(x,i+n);
            T.link(i+n,y);
        }
        else {
            int k=T.query(x,y);
            if(T.val[k]>e[i].b)
            {
                T.cut(e[k-n].u,k);
                T.cut(k,e[k-n].v);
                T.link(x,i+n);
                T.link(i+n,y);
            }
        }
        if(_find(1)==_find(n))
          ans=min(ans,e[i].a+T.val[T.query(1,n)]);
    //  printf("%d %d\n",e[i].a,T.query(1,n));
    }
    if(ans==inf) printf("-1");
    else printf("%d",ans);
    return 0;
}

 

posted @ 2018-07-25 19:21  logeadd  阅读(184)  评论(0编辑  收藏  举报