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\n",ans);
    }return 0;
}
posted @ 2017-05-16 12:11  forever97  阅读(157)  评论(0编辑  收藏  举报