bzoj3669: [Noi2014]魔法森林 lct版

先上题目 bzoj3669: [Noi2014]魔法森林

这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点

当然某两个点我用的是并查集维护 其实也可以在树上直接查询 但是这样比较方便 同时我们维护某个点极其子树的最大值所在的位置 每入一条边 如果两个端点已经联通就找出权值的边删掉之后连上新的边顺便更新答案 如果没联通就直接连上边就好 这样就解决问题了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=200007,inf=0x3f3f3f3f;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m,ans=inf;
int c[M][2],fa[M],p[M];
int mx[M],v[M],rev[M];
bool isrt(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
struct node{int a,b,u,v;}e[M];
bool cmp(node a,node b){return a.a<b.a;}
int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
void up(int x){
    int l=c[x][0],r=c[x][1];
    mx[x]=x;
    if(v[mx[l]]>v[mx[x]]) mx[x]=mx[l];
    if(v[mx[r]]>v[mx[x]]) mx[x]=mx[r];
}
void down(int x){
    int l=c[x][0],r=c[x][1];
    if(rev[x]){
        rev[x]=0; rev[l]^=1; rev[r]^=1;
        swap(c[x][0],c[x][1]);
    }
}
void rotate(int x){
    int y=fa[x],z=fa[y],l=0,r=1;
    if(c[y][1]==x) l=1,r=0;
    if(!isrt(y)) c[z][c[z][1]==y]=x;
    fa[y]=x; fa[x]=z; fa[c[x][r]]=y;
    c[y][l]=c[x][r]; c[x][r]=y;
    up(y); up(x);
}
int st[M],top;
void splay(int x){
    st[++top]=x; for(int i=x;!isrt(i);i=fa[i]) st[++top]=fa[i];
    while(top) down(st[top--]);
    while(!isrt(x)){
        int y=fa[x],z=fa[y];
        if(!isrt(y)){
            if(c[z][0]==y^c[y][0]==x) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void acs(int x0){
    for(int x=x0,y=0;x;splay(x),c[x][1]=y,up(x),y=x,x=fa[x]);
    splay(x0);
}
void mrt(int x){acs(x); rev[x]^=1;}
void link(int x,int y){mrt(x); fa[x]=y;}
void cut(int x,int y){mrt(x); acs(y); c[y][0]=fa[x]=0; up(y);}
int push_max(int x,int y){mrt(x); acs(y); return mx[y];}
int main()
{
    n=read(); m=read();
    for(int i=1;i<=n;i++) p[i]=i;
    for(int i=1;i<=m;i++) e[i].u=read(),e[i].v=read(),e[i].a=read(),e[i].b=read();
    sort(e+1,e+1+m,cmp);
    for(int i=1;i<=m;i++){
        int from=e[i].u,to=e[i].v,a=e[i].a,b=e[i].b;
        if(find(from)==find(to)){
            int now=push_max(from,to);
            if(v[now]>b){cut(now,e[now-n].v); cut(now,e[now-n].u);}
            else{
                if(find(1)==find(n)) ans=min(ans,a+v[push_max(1,n)]);
                continue;
            }
        }
        else p[find(from)]=find(to);
        v[i+n]=b; mx[i+n]=i+n;
        link(from,i+n); link(to,i+n);
        if(find(1)==find(n)) ans=min(ans,a+v[push_max(1,n)]);
    }
    if(ans==inf) printf("-1\n");
    else printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2017-06-13 22:00  友人Aqwq  阅读(150)  评论(0编辑  收藏  举报