BZOJ3669: [Noi2014]魔法森林(LCT)

传送门

题意
给一个无向图,每个边上有边权ai,bi,求一条路径,使得max(ai)+max(bi)最小。

题解
将a值排序后LCT暴力加边维护关于b值的最小生成树。

注意有一点是LCT不能维护边上的权值,只能维护点上的权值,所以要将每条连边上加一个点,Splay顺便维护最大值即可。

  • Code
#include<bits/stdc++.h>
using namespace std;
const int Maxn=5e4+50,Maxm=1e5+50;
const int INF=0x3f3f3f3f;

inline int read()
{
    char ch=getchar();int i=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
    return i*f;
}

struct edge
{
    int x,y,a,b;
    friend inline bool operator <(const edge &a,const edge &b)
    {
        return a.a<b.a;
    }
}e[Maxm];

struct node
{
    node *lc,*rc,*fa;
    node():lc(NULL),rc(NULL),fa(NULL){}
    int val,id,tag,maxx,id2;
}Pool[Maxn+Maxm],*pool=Pool,*tr[Maxn+Maxm];

int n,m,fa[Maxn],ans=INF;

inline int getf(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=getf(fa[x]);
}

inline void update(node *x)
{
    if(x->val>=(x->lc?x->lc->maxx:0))
    {
        if(x->val>=(x->rc?x->rc->maxx:0))x->id2=x->id,x->maxx=x->val;
        else x->id2=x->rc->id2,x->maxx=x->rc->maxx;
    }
    else if(x->val>=(x->rc?x->rc->maxx:0))
    {
        x->id2=x->lc->id2,x->maxx=x->lc->maxx;
    }
    else
    {
        if((x->rc?x->rc->maxx:0)>=(x->lc?x->lc->maxx:0))x->id2=x->rc->id2,x->maxx=x->rc->maxx;
        else x->id2=x->lc->id2,x->maxx=x->lc->maxx;
    }
}

inline bool isroot(node *x)
{
    return (!x->fa)||(x->fa->lc!=x&&x->fa->rc!=x);
}

inline bool which(node *x)
{
    return x->fa->lc!=x;
}

inline void pushdown(node *x)
{
    if(x->tag)
    {
        swap(x->lc,x->rc);
        if(x->lc)x->lc->tag^=1;
        if(x->rc)x->rc->tag^=1;
        x->tag^=1;
    }
}

inline void rotate(node *x)
{
    node *y=x->fa,*z=y->fa;
    if(!isroot(y))((z->lc==y)?(z->lc):(z->rc))=x;
    x->fa=z,y->fa=x;
    if(y->lc==x)
    {
        node *b=x->rc;
        x->rc=y;
        y->lc=b;
        if(b)b->fa=y;
    }
    if(y->rc==x)
    {
        node *b=x->lc;
        x->lc=y;
        y->rc=b;
        if(b)b->fa=y;
    }
    update(y);update(x);
}
inline void splay(node *x)
{
    static node* que[Maxn+Maxm];
    static int tail;
    que[tail=1]=x;
    for(node *y=x;!isroot(y);y=y->fa)que[++tail]=y->fa;
    for(int i=tail;i>=1;i--)pushdown(que[i]);
    while(!isroot(x))
    {
        node *y=x->fa;
        if(!isroot(y))
            (which(x)^which(y))?(rotate(x)):(rotate(y));
        rotate(x);
    }
}

inline void access(node *x)
{
    for(node *y=NULL;x;y=x,x=x->fa)splay(x),x->rc=y,update(x);
}

inline void makeroot(node *x)
{
    access(x);splay(x);x->tag^=1;
}

inline void cut(node *x,node *y)
{
    makeroot(x);access(y);splay(y);
    y->lc->fa=NULL;y->lc=NULL;update(y);
}

inline void link(node *x,node *y)
{
    makeroot(x);x->fa=y;
}

inline int select(node *x,node *y)
{
    makeroot(x);access(y);splay(y);
    return y->id2;
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)tr[i]=++pool,fa[i]=i,tr[i]->id=tr[i]->id2=i;
    for(int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read();
    sort(e+1,e+m+1);
    for(int i=1;i<=m;i++)tr[i+n]=++pool,tr[i+n]->val=e[i].b,tr[i+n]->id=tr[i+n]->id2=i+n,tr[i+n]->maxx=e[i].b;
    for(int i=1;i<=m;i++)
    {
        int x=e[i].x,y=e[i].y,a=e[i].a,b=e[i].b;
        if(x==y)continue;
        if(getf(x)!=getf(y)){fa[fa[x]]=fa[y],link(tr[x],tr[i+n]);link(tr[i+n],tr[y]);}
        else
        {
            int id=select(tr[x],tr[y]);
            if(e[id-n].b>e[i].b)
            {
                cut(tr[x],tr[id]);cut(tr[y],tr[id]);
                link(tr[x],tr[i+n]);link(tr[i+n],tr[y]);
            }
        }
        if(getf(1)==getf(n))
        {
            int id=select(tr[1],tr[n]);
            if(ans>e[i].a+e[id-n].b)ans=e[i].a+e[id-n].b;
        }
    }
    printf("%d\n",(ans==INF)?(-1):ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值