zoukankan      html  css  js  c++  java
  • 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
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Js高程:教你如何写出可维护的代码
    ES6 尾调用和尾递归
    js判断对象是否为空对象,判断对象中是否有某属性
    WebSocket断开原因、心跳机制防止自动断开连接
    Js闭包使用姿势指南
    浏览器事件模型
    Js数组排序
    简单的前端错误处理
    移动端做弹窗类页面注意事项
    加载时常统计
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7003757.html
Copyright © 2011-2022 走看看