zoukankan      html  css  js  c++  java
  • BZOJ 3669 [Noi2014]魔法森林(贪心+LCT)

    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3669

    【题目大意】

      给出一张图,每条边上有两个值ai和bi,现在需要求出一条1到N的路,
      求使得路上ai的最大值与bi的最大值的和最小。

    【题解】

      我们按照ai的权值从小到大排序,依次加边,我们只要求出bi最大值最小的生成路即可,
      我们加入边的时候如果发现之前两个点是相连的,并且路径中bi最大值比当前加入的边要大,
      那么我们把原来大的那条边cut掉,加入现在这条边。
      动态树对于边的处理可以将边权转化为点权。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring> 
    using namespace std;
    const int N=200010,INF=0x3f3f3f3f;
    int f[N],son[N][2],val[N],mx[N],tmp[N],from[N];bool rev[N];
    bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
    void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
    void up(int x){
        mx[x]=val[x],from[x]=x;
        if(son[x][0])if(mx[son[x][0]]>mx[x])mx[x]=mx[son[x][0]],from[x]=from[son[x][0]];
        if(son[x][1])if(mx[son[x][1]]>mx[x])mx[x]=mx[son[x][1]],from[x]=from[son[x][1]];
    }
    void rotate(int x){
        int y=f[x],w=son[y][1]==x;
        son[y][w]=son[x][w^1];
        if(son[x][w^1])f[son[x][w^1]]=y;
        if(f[y]){
            int z=f[y];
            if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
        }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    void splay(int x){
        int s=1,i=x,y;tmp[1]=i;
        while(!isroot(i))tmp[++s]=i=f[i];
        while(s)pb(tmp[s--]);
        while(!isroot(x)){
            y=f[x]; 
            if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
            rotate(x);
        }up(x);
    }
    void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
    int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
    void makeroot(int x){access(x);splay(x);rev1(x);}
    void link(int x,int y){makeroot(x);f[x]=y;access(x);}
    void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
    void cut(int x,int y){makeroot(x);cutf(y);}
    int ask(int x,int y){makeroot(x);access(y);splay(y);return mx[y];}
    int askfrom(int x,int y){makeroot(x);access(y);splay(y);return from[y];}
    void init(){
        memset(son,0,sizeof(son));
        memset(rev,0,sizeof(rev));
        memset(f,0,sizeof(f));
        memset(val,0,sizeof(val));
    }
    struct edge{int x,y,a,b;}e[N];
    bool cmp(edge a,edge b){return a.a<b.a;}
    int n,m;
    int main(){
        while(~scanf("%d%d",&n,&m)){
            init();
            int ans=INF;
            for(int i=1;i<=m;i++)scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].a,&e[i].b);
            sort(e+1,e+m+1,cmp);
            for(int i=1;i<=m;i++)val[n+i]=e[i].b,from[n+i]=n+i;
            for(int i=1;i<=m;i++){
                if(root(e[i].x)!=root(e[i].y))link(e[i].x,n+i),link(e[i].y,n+i);
                else{
                    int pos=askfrom(e[i].x,e[i].y);
                    if(e[i].b<val[pos]){
                        cut(pos,e[pos-n].x),cut(pos,e[pos-n].y);
                        link(e[i].x,n+i),link(e[i].y,n+i);
                    }
                }if(root(1)==root(n))ans=min(ans,e[i].a+ask(1,n));
            }if(ans==INF)puts("-1");
            else printf("%d
    ",ans);
        }return 0;
    }
  • 相关阅读:
    笨办法学Python——学习笔记4
    意识、语言、文字和程序感想
    笨办法学Python——学习笔记3
    把vim作为shell ide
    HDUYuna's confusion 树状数组 Or Multiset
    POJ3252 Round Numbers 组合数学
    HDU3874 Necklace 树状数组+离线处理
    UVA10212 The Last Nonzero Digit. 分解质因子+容斥定理
    HDU1041 Computer Transformation 大数
    HDUFish买电脑 二分查找
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj3669.html
Copyright © 2011-2022 走看看