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

    传送门

    如果一条边只要考虑 $a$ 的限制,那么显然最小生成树

    但是现在有 $a,b$ 两个限制,所以考虑按 $a$ 从小到大枚举边,动态维护 $b$ 的最小生成树

    考虑新加入的一条边 $x,y$ ,如果 $x,y$ 不在一颗树上显然直接加入,如果在一棵树上,考虑原本树上 $x$ 到 $y$ 的路径上 $b$ 最大的边

    如果比当前边大,那么就把原本那条边从最小生成树上删除,把新的边加进去

    答案就在每次加边时更新就好了

    这个东西显然直接 $LCT$ 维护,为了维护边权所以要把边权也看成点

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=4e5+7,INF=1e9+7;
    int n,m,ANS=INF;
    struct dat{
        int x,y,a,b;
        inline bool operator < (const dat &tmp) const {
            return a<tmp.a;
        }
    }d[N];
    int c[N][2],fa[N],t[N],val[N];
    //把边化成点后,t维护点权最大的点的编号,val[x]存点x的b值
    //边的编号为n+1到n+m
    bool rev[N];
    inline void pushdown(int x)
    {
        if(!rev[x]||!x) return;
        int &lc=c[x][0],&rc=c[x][1];
        rev[x]=0; swap(lc,rc);
        if(lc) rev[lc]^=1;
        if(rc) rev[rc]^=1;
    }
    inline void rever(int x) { rev[x]^=1; pushdown(x); }
    inline void pushup(int x)
    {
        t[x]=x;
        if(val[ t[c[x][0]] ] > val[t[x]]) t[x]=t[c[x][0]];
        if(val[ t[c[x][1]] ] > val[t[x]]) t[x]=t[c[x][1]];
    }
    inline bool notroot(int x) { return (c[fa[x]][0]==x)|(c[fa[x]][1]==x); }
    inline void rotate(int x)
    {
        int y=fa[x],z=fa[y],d=(c[y][1]==x);
        if(notroot(y)) c[z][c[z][1]==y]=x;
        fa[x]=z; fa[y]=x; fa[c[x][d^1]]=y;
        c[y][d]=c[x][d^1]; c[x][d^1]=y;
        pushup(y); pushup(x);
    }
    inline void push_rev(int x)
    {
        if(notroot(x)) push_rev(fa[x]);
        else pushdown(x);
        pushdown(c[x][0]); pushdown(c[x][1]);
    }
    inline void splay(int x)
    {
        push_rev(x);
        while(notroot(x))
        {
            int y=fa[x],z=fa[y];
            if(notroot(y))
            {
                if(c[y][0]==x ^ c[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),c[x][1]=y,pushup(x);
    }
    inline void makeroot(int x) { access(x); splay(x); rever(x); }
    inline int findroot(int x)
    {
        access(x); splay(x); pushdown(x);
        while(c[x][0]) pushdown(c[x][0]),x=c[x][0];
        splay(x);
        return x;
    }
    inline int split(int x,int y) { makeroot(x); access(y); splay(y); return t[y]; }//提取一段路径上点权最大的点的编号
    inline void link(int x,int y) { makeroot(x); if(findroot(y)!=x) fa[x]=y; }
    inline void cut(int x,int y)
    {
        makeroot(x);
        if(findroot(y)!=x||fa[y]!=x||c[y][0]) return;
        c[x][1]=fa[y]=0; pushup(x);
    }
    inline void query(int a)//更新答案
    {
        if(findroot(1)==findroot(n))//如果在同一颗树上
        {
            int w=split(1,n);
            ANS=min(ANS,a+val[w]);
        }
    }
    inline void insert(int i)//加入边
    {
        int x=d[i].x,y=d[i].y,a=d[i].a,b=d[i].b; bool flag=1;
        if(findroot(x)==findroot(y))//如果原本已经是一颗树
        {
            int w=split(x,y);
            if(val[w]>b) cut(w,d[w-n].x),cut(w,d[w-n].y);//如果b更小才cut
            else flag=0;//否则不连边
        }
        if(flag) link(n+i,x),link(n+i,y),query(a);//连边并更新ANS
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=m;i++)
            d[i].x=read(),d[i].y=read(),d[i].a=read(),d[i].b=read();
        sort(d+1,d+m+1);
        for(int i=1;i<=m;i++) val[n+i]=d[i].b;
        for(int i=1;i<=m;i++) insert(i);
        printf("%d",ANS <1e9 ? ANS : -1);
        return 0;
    }

     

  • 相关阅读:
    @RequestParam注解使用:Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.
    cglib动态代理导致注解丢失问题及如何修改注解允许被继承
    springboot Autowired BeanNotOfRequiredTypeException
    git根据用户过滤提交记录
    不同包下,相同数据结构的两个类进行转换
    How to use Jackson to deserialise an array of objects
    jooq实践
    java如何寻找main函数对应的类
    Python--matplotlib
    Python 和 Scikit-Learn
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10584416.html
Copyright © 2011-2022 走看看