• BZOJ3669(NOI2014):魔法森林 (LCT维护最小生成树)


    为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。
    初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。 魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。
    小E可以借助它们的力量,达到自己的目的。 只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型
    守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。 由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精
    灵的个数之和。 Input 第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai
    与Bi的含义如题所述。 注意数据中可能包含重边与自环。 Output 输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“
    -1”(不含引号)。 Sample Input 【输入样例1】 4 5 1 2 19 1 2 3 8 12 2 4 12 15 1 3 17 8 3 4 1 17 【输入样例2】 3 1 1 2 1 1 Sample Output 【输出样例1】 32 【样例说明1】 如果小E走路径1→24,需要携带19+15=34个守护精灵; 如果小E走路径1→34,需要携带17+17=34个守护精灵; 如果小E走路径1→234,需要携带19+17=36个守护精灵; 如果小E走路径1→324,需要携带17+15=32个守护精灵。 综上所述,小E最少需要携带32个守护精灵。 【输出样例2】 -1 【样例说明2】 小E无法从1号节点到达3号节点,故输出-1。 Hint 2<=n<=50,000 0<=m<=100,000 1<=ai ,bi<=50,000

    题意:给定一个无向图,每条边有两个权值ai和bi,从1走到N,设路径上a权的最大值为A,b权的最大值为B,求A+B的最小值。n<=5*1e4. m<=5*1e4。

    思路:要生成最小生成树(至少满足1和N连通),我们选择的边如果按A递增,那么易得B递减。现在按a从小到大排序,得到对于每个a,找到对应的b下限,如果连通,则更新答案。

    具体可以看这里:http://www.cnblogs.com/hua-dong/p/8665998.html

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=200010;
    const int inf=1000000000;
    struct edge{
        int x,y,a,b;
    
    }e[maxn];    
    bool cmp (edge w,edge v){
        return w.a<v.a;
    }
    void read(int &x){
        char c=getchar(); x=0;
        for(;c>'9'||c<'0';c=getchar());
        for(;c<='9'&&c>='0';c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    }
    struct LCT
    {
        int Max[maxn],rev[maxn],ch[maxn][2],fa[maxn],stc[maxn],top;
        int isroot(int x){
            return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
        }
        int get(int x){
            return ch[fa[x]][1]==x;
        }
        void pushdown(int x)
        {
            if(!rev[x]||!x) return ;
            swap(ch[x][0],ch[x][1]);
            if(ch[x][0]) rev[ch[x][0]]^=1; 
            if(ch[x][1]) rev[ch[x][1]]^=1; 
            rev[x]=0;
        }
        void pushup(int x)
        {
            Max[x]=x;
            if(ch[x][0]&&e[Max[ch[x][0]]].b>e[Max[x]].b) Max[x]=Max[ch[x][0]];
            if(ch[x][1]&&e[Max[ch[x][1]]].b>e[Max[x]].b) Max[x]=Max[ch[x][1]];
        }
        void rotate(int x)
        {
            int old=fa[x],fold=fa[old],opt=get(x);
            if(!isroot(old)) ch[fold][get(old)]=x;
            fa[x]=fold;
            ch[old][opt]=ch[x][opt^1]; fa[ch[old][opt]]=old;
            ch[x][opt^1]=old; fa[old]=x; 
            pushup(old); pushup(x);
        }
        void splay(int x)
        {
            int top=0; stc[++top]=x;
            for(int i=x;!isroot(i);i=fa[i]) stc[++top]=fa[i];
            for(int i=top;i;i--) pushdown(stc[i]);
            for(int f;!isroot(x);rotate(x)){
                if(!isroot(f=fa[x]))
                  rotate(get(x)==get(f)?f:x);
            }        
        }
        void access(int x)
        {
            int rson=0;
            for(;x;rson=x,x=fa[x]){
                splay(x);
                ch[x][1]=rson;
                pushup(x);
            }
        }
        int find(int x){ access(x); splay(x); while(ch[x][0]) x=ch[x][0]; return x;}
        int query(int x,int y) { make_root(y); access(x);  splay(x); return Max[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; splay(x); }
        void cut(int x,int y) { make_root(x); access(y); splay(y); fa[x]=ch[y][0]=0; }    
    }S;
    int main()
    {
        int N,M,i,ans=inf;
        read(N); read(M);
        for(i=1;i<=M;i++){
            read(e[i].x); read(e[i].y); 
            read(e[i].a); read(e[i].b); 
        }
        sort(e+1,e+M+1,cmp);
        for(i=1;i<=M;i++){
            if(S.find(M+e[i].x)!=S.find(M+e[i].y)) {
                 S.link(i,M+e[i].x);
                 S.link(i,M+e[i].y);
            }
            else{
                int tmp=S.query(M+e[i].x,M+e[i].y);
                if(e[tmp].b>e[i].b) {
                    S.cut(tmp,M+e[tmp].x); S.cut(tmp,M+e[tmp].y);
                    S.link(i,M+e[i].x); S.link(i,M+e[i].y);
                }
            }
            if(S.find(M+1)==S.find(M+N)){
                int tmp=S.query(M+1,M+N);
                if(e[tmp].b+e[i].a<ans) ans=e[tmp].b+e[i].a;
            }
        }
        if(ans==inf) ans=-1;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    【矩阵乘法优化dp】[Codeforces 621E] Wet Shark and Blocks
    【2016常州一中夏令营Day7】
    【2016常州一中夏令营Day6】
    【2016常州一中夏令营Day5】
    【2016常州一中夏令营Day4】
    【2016常州一中夏令营Day3】
    【2016常州一中夏令营Day2】
    Aiopr的中文意思
    Bloom filter
    redis4.0.2集群搭建
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8696447.html
Copyright © 2020-2023  润新知