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;
    }
  • 相关阅读:
    LeetCode Best Time to Buy and Sell Stock
    LeetCode Scramble String
    LeetCode Search in Rotated Sorted Array II
    LeetCode Gas Station
    LeetCode Insertion Sort List
    LeetCode Maximal Rectangle
    Oracle procedure
    浏览器下载代码
    Shell check IP
    KVM- 存储池配置
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj3669.html
Copyright © 2011-2022 走看看