• 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
    ********************/
    
  • 相关阅读:
    python
    基于vue的npm发包
    div实现水平垂直居中
    element-ui中表格添加fixed定位列后 出现表格错位现象
    解决github经常无法访问的问题
    快排算法C语言实现
    ubuntu下qt运行时/usr/bin/ld: cannot find -lGL
    llinux装完qt 启动qtcreator报错
    LINUX权限-bash: ./startup.sh: Permission denied
    In short, don’t use a pointer to a string literal if you plan to alter the string.
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/9118480.html
Copyright © 2020-2023  润新知