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

    传送门

    这题似乎不好直接做,可以考虑按照(a_i)升序排序,然后依次加边更新答案

    具体实现方法是用lct维护当前的树,这里需要维护链上最大的(b_i).每次加一条边,如果加完以后没有环直接加,否则找出链上最大的(b_i),如果这个(b_i)比当前的(b_i)小,加了肯定不优,否则就把那条边断掉,加上这条边.每次用当前(a_i)和1到n链上最大(b_i)更新答案

    #include<bits/stdc++.h>
    #define LL long long
    #define db long double
    #define il inline
    
    using namespace std;
    const int N=1e5+10;
    il LL rd()
    {
        LL x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int n,m,w[N],po[N][2],tt;
    int fa[N],ch[N][2],id[N],vi[N];
    bool tg[N];
    bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    void psup(int x)
    {
        id[x]=w[id[ch[x][0]]]>w[id[ch[x][1]]]?id[ch[x][0]]:id[ch[x][1]];
        id[x]=w[id[x]]>w[vi[x]]?id[x]:vi[x];
    }
    void rev(int x){if(x) swap(ch[x][0],ch[x][1]),tg[x]^=1;}
    void psdn(int x){if(tg[x]) rev(ch[x][0]),rev(ch[x][1]),tg[x]=0;}
    void ppush(int x)
    {
        if(nrt(x)) ppush(fa[x]);
        psdn(x);
    }
    void rot(int x)
    {
        int y=fa[x],z=fa[y],yy=ch[y][1]==x,w=ch[x][!yy];
        if(nrt(y)) ch[z][ch[z][1]==y]=x;
        ch[y][yy]=w,ch[x][!yy]=y;
        if(w) fa[w]=y;
        fa[x]=z,fa[y]=x;
        psup(y);
    }
    void spl(int x)
    {
        ppush(x);
        while(nrt(x))
        {
            int y=fa[x];
            if(nrt(y)) ((ch[y][1]==x)^(ch[fa[y]][1]==y))?rot(x):rot(y);
            rot(x);
        }
        psup(x);
    }
    void acs(int x)
    {
        for(int y=0;x;y=x,x=fa[x])
            spl(x),ch[x][1]=y,psup(x);
    }
    void mkrt(int x)
    {
        acs(x),spl(x),rev(x);
    }
    int fdrt(int x)
    {
        acs(x),spl(x);
        psdn(x);
        while(ch[x][0]) x=ch[x][0],psdn(x);
        return x;
    }
    void split(int x,int y)
    {
        mkrt(x),acs(y),spl(y);
    }
    void link(int x,int y,int z)
    {
        mkrt(x);
        if(fdrt(y)!=x)
        {
            mkrt(y);
            w[++tt]=z,vi[tt]=tt,po[tt][0]=x,po[tt][1]=y;
            fa[x]=fa[y]=tt;
            return;
        }
        acs(y),spl(y);
        int ii=id[y];
        if(w[ii]<=z) return;
        mkrt(po[ii][0]),acs(po[ii][1]),spl(ii);
        fa[po[ii][0]]=fa[po[ii][1]]=ch[ii][0]=ch[ii][1]=0,psup(ii);
        w[ii]=z,po[ii][0]=x,po[ii][1]=y;
        mkrt(x),mkrt(y);
        fa[x]=fa[y]=ii;
    }
    struct edge
    {
        int x,y,a,b;
        bool operator < (const edge &bb) const {return a<bb.a;}
    }e[N];
    
    int main()
    {
        n=rd(),m=rd();
        for(int i=1;i<=m;++i)
        {
            int x=rd(),y=rd(),a=rd(),b=rd();
            e[i]=(edge){x,y,a,b};
        }
        sort(e+1,e+m+1);
        tt=n,w[0]=-(1<<30);
        int ans=1<<30;
        for(int i=1;i<=m;++i)
        {
            if(e[i].x==e[i].y) continue;
            link(e[i].x,e[i].y,e[i].b);
            mkrt(1);
            if(fdrt(n)==1) ans=min(ans,e[i].a+w[id[n]]);
        }
        printf("%d
    ",ans<(1<<29)?ans:-1);
        return 0; 
    }
    
  • 相关阅读:
    LAPACK(5)——矩阵广义特征值问题和QZ分解
    数据结构与算法——堆
    STL(1)——查找函数find的使用
    数据结构与算法——多项式
    LAPACK(6)——总结
    设计模式代理模式
    C#防盗链
    设计模式组合模式
    JavascriptFolder对象
    JavascriptTextStream对象
  • 原文地址:https://www.cnblogs.com/smyjr/p/10659708.html
Copyright © 2011-2022 走看看