zoukankan      html  css  js  c++  java
  • 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型守护精灵的个数之和。
    题解:lct维护最小生成树,先按a排序,然后挨个加边当有有回路时删掉最大的那个b边,然后当1和n联通时,每次都要算一下a和最大的b的和,就相当于把a遍历加边,然后保证联通的情况下找最小的b,
    lct维护连通性,把边权转化为点权,每个边变成一个点,向两端各连一条边,然后加边和删边都很方便了

    /**************************************************************
        Problem: 3669
        User: walfy
        Language: C++
        Result: Accepted
        Time:6608 ms
        Memory:9136 kb
    ****************************************************************/
     
    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    //#pragma GCC optimize("unroll-loops")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define ld long double
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define fio ios::sync_with_stdio(false);cin.tie(0)
     
    using namespace std;
     
    const double eps=1e-6;
    const int N=200000+10,maxn=100000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
     
    struct LCT{
        int fa[N],ch[N][2],rev[N],ma[N],val[N],id[N],q[N];
        inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
        inline void pushup(int x)
        {
            id[x]=x;ma[x]=val[x];
            if(ma[x]<ma[ch[x][0]])
            {
                ma[x]=ma[ch[x][0]];
                id[x]=id[ch[x][0]];
            }
            if(ma[x]<ma[ch[x][1]])
            {
                ma[x]=ma[ch[x][1]];
                id[x]=id[ch[x][1]];
            }
        }
        inline void pushdown(int x)
        {
            if(rev[x])
            {
                rev[x]=0;swap(ch[x][0],ch[x][1]);
                rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
            }
        }
        inline void Rotate(int x)
        {
            int y=fa[x],z=fa[y],l,r;
            if(ch[y][0]==x)l=0,r=l^1;
            else l=1,r=l^1;
            if(!isroot(y))
            {
                if(ch[z][0]==y)ch[z][0]=x;
                else ch[z][1]=x;
            }
            fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
            ch[y][l]=ch[x][r];ch[x][r]=y;
            pushup(y);pushup(x);
        }
        inline void splay(int x)
        {
            int top=1;q[top]=x;
            for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
            for(int i=top;i;i--)pushdown(q[i]);
            while(!isroot(x))
            {
                int y=fa[x],z=fa[y];
                if(!isroot(y))
                {
                    if((ch[y][0]==x)^(ch[z][0]==y))Rotate(x);
                    else Rotate(y);
                }
                Rotate(x);
            }
        }
        inline void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,pushup(x);}
        inline void makeroot(int x){access(x),splay(x),rev[x]^=1;}
        inline int findroot(int x){access(x),splay(x);while(ch[x][0])x=ch[x][0];return x;}
        inline void split(int x,int y){makeroot(x),access(y),splay(y);}
        inline void cut(int x,int y){split(x,y);if(ch[y][0]==x)ch[y][0]=0,fa[x]=0;}
        inline void link(int x,int y){makeroot(x),fa[x]=y,splay(x);}
    }lct;
    struct edge{
        int u,v,a,b;
        bool operator <(const edge &rhs)const{
            return a<rhs.a || (a==rhs.a && b<rhs.b);
        }
    }e[maxn];
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].a,&e[i].b);
        sort(e+1,e+1+m);
        for(int i=1;i<=m;i++)
        {
            lct.val[i+n]=lct.ma[i+n]=e[i].b;
            lct.id[i+n]=i+n;
        }
        int ans=inf;
        for(int i=1;i<=m;i++)
        {
            int fx=lct.findroot(e[i].u),fy=lct.findroot(e[i].v);
            if(fx!=fy)lct.link(e[i].u,i+n),lct.link(e[i].v,i+n);
            else
            {
                lct.split(e[i].u,e[i].v);
    //            printf("%d--
    ",lct.ch[e[i].v][0]);
                if(lct.ma[e[i].v]>e[i].b)
                {
                    int p=lct.id[e[i].v]-n;
    //                printf("%d %d++
    ",lct.id[e[i].v],lct.ma[e[i].v]);
                    lct.cut(e[p].u,p+n);lct.cut(e[p].v,p+n);
                    lct.link(e[i].u,i+n),lct.link(e[i].v,i+n);
                }
            }
            fx=lct.findroot(1),fy=lct.findroot(n);
            if(fx==fy)
            {
                lct.split(1,n);
    //            printf("%d 
    ",lct.ma[n]);
                ans=min(ans,e[i].a+lct.ma[n]);
            }
        }
        printf("%d
    ",ans>=inf?-1:ans);
        return 0;
    }
    /********************
    4 5
    3 4 1 17
    2 3 8 12
    2 4 12 15
    1 3 17 8
    1 2 19 1
    ********************/
    
  • 相关阅读:
    Using Resource File on DotNet
    C++/CLI VS CSharp
    JIT VS NGen
    [Tip: disable vc intellisense]VS2008 VC Intelisense issue
    UVa 10891 Game of Sum(经典博弈区间DP)
    UVa 10723 Cyborg Genes(LCS变种)
    UVa 607 Scheduling Lectures(简单DP)
    UVa 10401 Injured Queen Problem(简单DP)
    UVa 10313 Pay the Price(类似数字分解DP)
    UVa 10635 Prince and Princess(LCS N*logN)
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/9118480.html
Copyright © 2011-2022 走看看