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

    P2387 [NOI2014]魔法森林

    LCT边权维护经典题

    咋维护呢?边化为点,边权变点权。

    本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树

    加边后出现环咋办?

    splay维护最大边的编号,找到最大边删除再加新边就ok辣

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline void Swap(int &a,int &b){a^=b^=a^=b;}
    inline int Min(int a,int b){return a<b?a:b;}
    void read(int &x){
        static char c=getchar();x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
    }
    #define N 200005
    struct edge{int f,t,A,B;}a[N];
    int n,m,ans=2e9,ch[N][2],fa[N],val[N],s[N],rev[N],dad[N];
    #define lc ch[x][0]
    #define rc ch[x][1]
    inline bool cmp(edge P,edge Q){return P.A<Q.A;}
    int find(int x){return dad[x]==x?x:dad[x]=find(dad[x]);}
    inline bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    void up(int x){//维护平衡树上最大点权的点的编号(就是边化为的点)
        s[x]=x;
        if(val[s[lc]]>val[s[x]]) s[x]=s[lc];
        if(val[s[rc]]>val[s[x]]) s[x]=s[rc];    
    }
    void Rev(int x){Swap(lc,rc); rev[x]^=1;}
    void down(int x){if(rev[x]) Rev(lc),Rev(rc),rev[x]=0;}
    void Pre(int x){if(nrt(x))Pre(fa[x]); down(x);}
    void turn(int x){
        int y=fa[x],z=fa[y],l=(ch[y][1]==x),r=l^1;
        if(nrt(y)) ch[z][ch[z][1]==y]=x;
        fa[ch[x][r]]=y; fa[y]=x; fa[x]=z;
        ch[y][l]=ch[x][r]; ch[x][r]=y;
        up(y); up(x);
    }
    void splay(int x){
        Pre(x);
        for(;nrt(x);turn(x)){
            int y=fa[x],z=fa[y];
            if(nrt(y)) turn(((ch[z][1]==y)^(ch[y][1]==x))?x:y);
        }
    }
    void access(int x){for(int y=0;x;y=x,x=fa[x]) splay(x),rc=y,up(x);}
    void makert(int x){access(x);splay(x);Rev(x);}
    int findrt(int x){
        access(x);splay(x);down(x);
        while(lc) x=lc,down(x);
        splay(x); return x;
    }
    void link(int x,int y){makert(x); if(findrt(y)!=x)fa[x]=y;}
    void cut(int x,int y){
        makert(x);
        if(findrt(y)==x&&fa[y]==x&&!ch[y][0]) fa[y]=rc=0,up(x);
    }
    void split(int x,int y){makert(x);access(y);splay(y);}
    int main(){
        read(n);read(m); register int i;
        for(i=1;i<=n+m;++i) dad[i]=i;
        for(i=1;i<=m;++i)
            read(a[i].f),read(a[i].t),read(a[i].A),read(a[i].B);
        sort(a+1,a+m+1,cmp);
        for(i=1;i<=m;++i) val[n+i]=a[i].B;
        for(i=1;i<=m;++i){
            int r1=find(a[i].f),r2=find(a[i].t),e;//并查集维护是否连通
            if(r1==r2){
                split(a[i].f,a[i].t); e=s[a[i].t];
                if(val[e]<=a[i].B) continue;
                cut(a[e-n].f,e); cut(e,a[e-n].t);//删掉最大边
            }else dad[r1]=r2;
            link(a[i].f,i+n); link(i+n,a[i].t);
            if(find(1)==find(n)) split(n,1),ans=Min(ans,a[i].A+val[s[1]]);
        }
        if(ans>=2e9) puts("-1");
        else printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    idea 文件名乱码问题的解决
    <context:component-scan>使用说明
    <mvc:annotation-driven />
    mac下的一些常识
    centos下的防火墙配置
    mac 下安装nginx
    centos下安装nginx
    Centos-统计文件或目录占用磁盘空间-du
    Centos-查看磁盘分区占用情况-df
    Centos-重定向方式打包、备份、还原、恢复工具-cpio
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10568229.html
Copyright © 2011-2022 走看看