zoukankan      html  css  js  c++  java
  • [NOI2014]魔法森林

    Description:

    给定一个无向连通图,每条边有两个属性,(a_i,b_i),找一条从1号点到n号点的路径,使路径上的 ({max}a_{i}+maxb_{i}) 最小

    Hint:

    (n=5*10^4,m<=10^5)

    Solution:

    一看到题目就想到最短路,然后发现行不通

    最短路行不通,那就考虑最小生成树

    一个属性显然可以直接做

    但是现在有两个属性

    考虑按边权枚举其中一个属性

    即按 (ai) 排序后每次向图中加入一条边

    同时维护以 (bi) 为边权的最小生成树

    若成环,选择一条 (bi) 较小的边

    每次加边后更新1到n的答案

    维护最小生成树用 (lct) 解决

    #include<bits/stdc++.h>
    using namespace std;
    const int mxn=1e6+5,inf=1e9;
    struct ed {
        int u,v,w,z,id;
    }q[mxn];
    int n,m,tot,mx[mxn],fa[mxn],ch[mxn][2],rev[mxn],st[mxn],val[mxn];
    pair<int ,int > g[mxn];
    map<pair<int ,int >,int > s;
    
    int cmp(ed x,ed y) {
        return x.w<y.w;
    }
    
    inline void checkmi(int &x,int y,int z) {
        if(x>y+z) x=y+z;
    }
    
    namespace lct {
        int isnotrt(int x) {
            return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
        }
        void push_up(int x) {
            mx[x]=x;
            if(val[mx[x]]<val[mx[ch[x][0]]]) mx[x]=mx[ch[x][0]];
            if(val[mx[x]]<val[mx[ch[x][1]]]) mx[x]=mx[ch[x][1]];
        }
        void push_down(int x) {
            if(rev[x]) {
                swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
                swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
                rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; rev[x]=0;
            }
        }
        void rotate(int x) {
            int y=fa[x],z=fa[y],tp=ch[y][1]==x;
            if(isnotrt(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;
            ch[y][tp]=ch[x][tp^1],fa[ch[x][tp^1]]=y;
            ch[x][tp^1]=y; fa[y]=x;
            push_up(y),push_up(x);
        }
        void splay(int x) {
            int tp=x,s=0; st[++s]=tp;
            while(isnotrt(tp)) st[++s]=tp=fa[tp];
            while(s) push_down(st[s]),--s;
            while(isnotrt(x)) {
                int y=fa[x],z=fa[y];
                if(isnotrt(y)) 
                    (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
                rotate(x);
            }
        }
        void access(int x) {
            for(int y=0;x;x=fa[y=x]) 
                splay(x),ch[x][1]=y,push_up(x);
        }
        void makert(int x) {
            access(x); splay(x);
            swap(ch[x][0],ch[x][1]); rev[x]^=1; 
        }
        int findrt(int x) {
            access(x); splay(x);
            while(ch[x][0]) push_down(x),x=ch[x][0];
            splay(x); return x;
        }
        void link(int x,int y) {
            makert(x); fa[x]=y;
        }
        void cut(int x,int y) {
            makert(x); access(y); splay(y);
            fa[x]=ch[y][0]=0; push_up(y);//
        }
        int query(int x,int y) {
            makert(x); access(y); splay(y);
            return mx[y];
        }
    }
    using namespace lct;
    
    int main()
    {
        scanf("%d%d",&n,&m); tot=n; int ans=inf;
        for(int i=1;i<=m;++i) {
            scanf("%d%d%d%d",&q[i].u,&q[i].v,&q[i].w,&q[i].z);
            s[make_pair(q[i].u,q[i].v)]=s[make_pair(q[i].v,q[i].u)]=++tot;
            val[tot]=q[i].z; g[tot]=make_pair(q[i].u,q[i].v);
        }
        sort(q+1,q+m+1,cmp);
        for(int i=1;i<=m;++i) {
            int u=q[i].u,v=q[i].v,w=s[make_pair(u,v)];
            if(findrt(u)!=findrt(v)) 
                link(u,w),link(w,v),mx[w]=w,val[w]=q[i].z;
            else {
                int tp=query(u,v); 
                if(val[tp]>q[i].z) {
                    cut(g[tp].first,tp);
                    cut(g[tp].second,tp);
                    link(u,w); link(v,w);
                    mx[w]=w,val[w]=q[i].z; 
                }
            }
            if(findrt(1)==findrt(n)) checkmi(ans,val[query(1,n)],q[i].w);
        }
        printf("%d",ans==inf?-1:ans);
    }
    
  • 相关阅读:
    670. Maximum Swap
    653. Two Sum IV
    639. Decode Ways II
    636. Exclusive Time of Functions
    621. Task Scheduler
    572. Subtree of Another Tree
    554. Brick Wall
    543. Diameter of Binary Tree
    535. Encode and Decode TinyURL
    博客园自定义背景图片
  • 原文地址:https://www.cnblogs.com/list1/p/10398164.html
Copyright © 2011-2022 走看看