• bzoj3669[Noi2014]魔法森林


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define maxn 150005
    #define maxm 100005
    #define pi pair<int,int>
    #define mp(a,b) make_pair(a,b)
    using namespace std;
    
    struct note{
        int u,v,a,b;
    }wi[maxm];
    int n,m,ans,fa[maxn],son[maxn][2],val[maxn],sm[maxn],sm_id[maxn];
    bool rev[maxn];
    
    bool comp(note x,note y){
        if (x.a==y.a) return x.b<y.b;
        return x.a<y.a;  
    }
    
    struct date{
        int which(int x){
            return son[fa[x]][1]==x;
        }
        int isroot(int x){
            return son[fa[x]][1]!=x&&son[fa[x]][0]!=x;
        }
        void update(int x){
            sm_id[x]=x,sm[x]=val[x];
            if (son[x][0]&&sm[son[x][0]]>sm[x]) sm[x]=sm[son[x][0]],sm_id[x]=sm_id[son[x][0]];
            if (son[x][1]&&sm[son[x][1]]>sm[x]) sm[x]=sm[son[x][1]],sm_id[x]=sm_id[son[x][1]];
        }
        void pushdown(int x){
            if (rev[x]){
                rev[x]^=1,swap(son[x][1],son[x][0]);
                if (son[x][0]) rev[son[x][0]]^=1;
                if (son[x][1]) rev[son[x][1]]^=1;
            }
        }
        void relax(int x){
            if (!isroot(x)) relax(fa[x]);
            pushdown(x);
        }
        void rotata(int x){
            int y=fa[x],d=which(x),dd=which(y);
            if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
            fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
            fa[y]=x,son[x][d^1]=y;
            update(y);
        }
        void splay(int x){
            relax(x);
            while (!isroot(x)){
                if (isroot(fa[x])) rotata(x);
                else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
                else rotata(x),rotata(x);
            }
            update(x);
        }
        void access(int x){
            for (int p=0;x;x=fa[x]){
                splay(x);
                son[x][1]=p;
                update(x);
                p=x;
            }
        }
        void make_root(int x){
            access(x);
            splay(x);
            rev[x]^=1;
        }
        void link(int x,int y){
            make_root(x);
            fa[x]=y;
        }
        void cut(int x,int y){
            make_root(x);
            access(y);
            splay(y);
            son[y][0]=fa[x]=0;
            update(y);
        }
        void split(int x,int y){
            make_root(x);
            access(y);
            splay(y);
        }
        int query(int x,int y){
            split(x,y);
            return sm[y];
        }
        pi find(int x,int y){
            split(x,y);
            return mp(sm_id[y],sm[y]);
        }
        int find_root(int x){
            access(x);
            splay(x);
            while (son[x][0]) x=son[x][0];
            return x;
        }
    }lct;
    
    int main(){
    //    freopen("forest.in","r",stdin);
    //    freopen("forest.out","w",stdout);
        memset(rev,0,sizeof(rev));
        memset(fa,0,sizeof(fa));
        memset(son,0,sizeof(son));
        memset(val,0,sizeof(val));
        memset(sm,0,sizeof(sm));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++) scanf("%d%d%d%d",&wi[i].u,&wi[i].v,&wi[i].a,&wi[i].b);
        sort(wi+1,wi+m+1,comp);
        for (int i=1;i<=n;i++) val[i]=0,lct.update(i);
        ans=maxn;
        pi temp;
        for (int i=1;i<=m;i++){
            int u=wi[i].u,v=wi[i].v;
            if (lct.find_root(u)!=lct.find_root(v)){
                val[n+i]=wi[i].b,lct.update(n+i);
                lct.link(n+i,u),lct.link(n+i,v);
            }else{
                temp=lct.find(u,v);
                if (temp.second<=wi[i].b) continue;
                else{
                    int t=temp.first;
                    lct.cut(wi[t-n].u,t),lct.cut(wi[t-n].v,t);
                    val[n+i]=wi[i].b,lct.update(n+i);
                    lct.link(n+i,u),lct.link(n+i,v);
                }
            }
            if (lct.find_root(1)!=lct.find_root(n)) continue;
            int t=lct.query(1,n);
            ans=min(ans,t+wi[i].a);
        }
        if (ans>maxm) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    View Code

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3669

    题目大意:给定一个无向图,每条边有两个权值va,vb,要求选一条从1到n的路径,满足这条路径上点的max(va)+max(vb)最小,若没有从A到B的路径,则输出-1。

    做法:初看这题,暴力写法:将边按va升序排序,枚举i,此时max(va)=vi,保证max(vb)最小即可,我们可以想到kruscal,并查集集维护即可,但是瓶颈在于每次都要将1~i的边按vb升序排序,在O(n)的加入,这种做法复杂度过高,不宜使用。

    仔细想想:我们可以考虑用lct维护这个过程,考虑先将边按va升序排序,然后依次加入每一条边,此时max(va)=vi,保证max(vb)最小即可,加入该边时会有两种情况:

    1.不形成环,则加入这条边,若节点1与节点n联通,则用1到n链上vb最大值+vi更新答案,否则不更新答案。

    2.形成环,与lct模拟kruscal的过程一样,删掉原本那条链上vb权值最大的边,并加入这条边,若节点1与节点n联通,则用1到n链上vb最大值+vi更新答案,否则不更新答案。

    lct+离线处理

  • 相关阅读:
    冒泡排序及优化
    Map的三种遍历
    抽象类以及接口的异同
    安卓仿制新浪微博(一)之OAuth2授权接口
    安卓handler.post问题
    Git——版本控制器概述
    Linux概述及简单命令
    JBoss7配置-支持IPv4和IPv6双栈环境
    作用域public,private,protected,以及不写时的区别
    UML类图画法及类之间几种关系
  • 原文地址:https://www.cnblogs.com/OYzx/p/5503356.html
Copyright © 2020-2023  润新知