BZOJ 3669 魔法森林 LCT

链接:【BZOJ 3669】
题意:一个无向图,每条边都有A,B两种权值,找出一条最优路径使得1~n路径上的两个权值的瓶颈之和最小。
思路:对于每条边按照A为关键字从小到大排序,枚举A的瓶颈加入边,若边的两点之间联通,则找出B最大的边并比较,若大于当前B,则将该边删去,否则不加入这条边。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int max_n=400010;
#define NIL pool
struct Node{
    int val;
    int pos,mpos;
    bool root,rev;
    int l,r;
    Node *lch,*rch,*fa;
    Node(){
        root=rev=false;
    }
    Node(int _val,int _pos,Node *_lch,Node *_rch,Node *_fa)
    :val(_val),pos(_pos),lch(_lch),rch(_rch),fa(_fa){
        mpos=pos;
        root=true;
        rev=false;
    }
}pool[max_n],*sp;
struct LCT{
    Node *node[max_n],*stk[max_n];
    int now_cnt;
    LCT(){}
    int max1(int a,int b){
        if(node[a]->val>node[b]->val)return a;
        return b;
    }
    void init(){
        new(NIL)Node(0,0,NIL,NIL,NIL);
        sp=NIL;
        node[0]=new(++sp)Node(0,0,NIL,NIL,NIL);
    }
    void build(int n){
        now_cnt=n;
        for(int i=1;i<=n;i++){
            node[i]=new(++sp)Node(0,0,NIL,NIL,NIL);
        }
    }
    void update(Node *t){
        if(t==NIL)return;
        t->mpos=max1(t->pos,max1(t->lch->mpos,t->rch->mpos));
    }
    void reverse(Node *t){
        if(t==NIL)return;
        t->rev^=1;
        swap(t->lch,t->rch);
    }
    void pushdown(Node *t){
        if(t==NIL)return;
        if(t->rev){
            t->rev=false;
            reverse(t->lch);
            reverse(t->rch);
        }
    }
    void zig(Node *t){
        Node *f=t->fa,*c=t->rch;
        if(f->root)t->root=true,f->root=false;
        else (f->fa->lch==f?f->fa->lch:f->fa->rch)=t;
        t->fa=f->fa,t->rch=f,f->lch=c,f->fa=t,c->fa=f;
        update(f);
    }
    void zag(Node *t){
        Node *f=t->fa,*c=t->lch;
        if(f->root)t->root=true,f->root=false;
        else (f->fa->lch==f?f->fa->lch:f->fa->rch)=t;
        t->fa=f->fa,t->lch=f,f->rch=c,f->fa=t,c->fa=f;
        update(f);
    }
    void splay(Node *t){
        Node *p=t;
        int top=0;
        stk[top]=t;
        while(!p->root){
            stk[++top]=p->fa;
            p=p->fa;
        }
        while(top>=0){
            pushdown(stk[top--]);
        }
        while(!t->root){
            if(t->fa->root){
                if(t->fa->lch==t)zig(t);
                else zag(t);
            }
            else {
                if(t->fa->fa->lch==t->fa){
                    if(t->fa->lch==t)zig(t->fa),zig(t);
                    else zag(t),zig(t);
                }
                else {
                    if(t->fa->lch==t)zig(t),zag(t);
                    else zag(t->fa),zag(t);
                }

            }
        }
        update(t);
    }
    void evert(Node *t){
        t=expose(t);
        reverse(t);
    }
    Node* expose(Node *t){
        Node *p=t,*q=NIL;
        while(p!=NIL){
            splay(p);
            p->rch->root=true;
            p->rch=q;
            p->rch->root=false;
            update(p);
            q=p;
            p=p->fa;
        }
        return q;
    }
    Node * getroot(Node *t){
        t=expose(t);
        while(1){
            if(t->lch!=NIL){
                t=t->lch;
            }
            else {
                return t;
            }
        }
    }
    void cut(int a,int b){
        evert(node[b]);
        expose(node[a]);
        splay(node[a]);
        if(node[a]->lch==node[b]){
            node[a]->lch->fa=NIL;
            node[a]->lch->root=true;
            node[a]->lch=NIL;
            update(node[a]);
        }
    }
    void link(int a,int b){
        if(getroot(node[a])==getroot(node[b])){
            cut_it(a,b);
        }
        evert(node[b]);
        splay(node[b]);
        node[b]->fa=node[a];
        expose(node[b]);
    }
    void Link(int a,int b,int val){
        apy_edge(a,b,val);
        link(a,now_cnt);
        link(b,now_cnt);
    }
    void apy_edge(int a,int b,int val){
        node[++now_cnt]=new(++sp)Node(val,now_cnt,NIL,NIL,NIL);
        node[now_cnt]->l=a;
        node[now_cnt]->r=b;
    }
    void cut_it(int a,int b){
        Node *p=node[b],*q=NIL;
        expose(node[a]);
        int ret;
        while(p!=NIL){
            splay(p);
            if(p->fa==NIL){
                ret=max1(p->pos,max1(p->rch->mpos,q->mpos));
            }
            p->rch->root=true;
            p->rch=q;
            q->root=false;
            update(p);
            q=p;
            p=p->fa;
        }
        cut(ret,node[ret]->l);
        cut(ret,node[ret]->r);
    }
    int querry(int a,int b){
        if(getroot(node[a])!=getroot(node[b]))return 1000000000;
        Node *p=node[b],*q=NIL;
        expose(node[a]);
        int ret;
        while(p!=NIL){
            splay(p);
            if(p->fa==NIL){
                ret=max1(p->pos,max1(p->rch->mpos,q->mpos));
            }
            p->rch->root=true;
            p->rch=q;
            q->root=false;
            update(p);
            q=p;
            p=p->fa;
        }
        return node[ret]->val;
    }
}T;

int rk[max_n];
int op[max_n][4];
bool cmp(int a,int b){
    return op[a][2]<op[b][2];
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        int ans=1e9;
        T.init();
        T.build(n);
        for(int i=0;i<m;i++){
            scanf("%d%d%d%d",op[i],op[i]+1,op[i]+2,op[i]+3);
            rk[i]=i;
        }
        sort(rk,rk+m,cmp);
        for(int i=0;i<m;i++){
            int tp=rk[i];
            int ttp=T.querry(op[tp][0],op[tp][1]);
            if(ttp>op[tp][3]){
                T.Link(op[tp][0],op[tp][1],op[tp][3]);
                ans=min(ans,op[tp][2]+T.querry(1,n));
            }
        }
        if(ans==1000000000)ans=-1;
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值