zoukankan      html  css  js  c++  java
  • [NOI2014]魔法森林

    题目

    首先这道题的生成树部分还是比较好想的,如果只有(a)(b)一个限制,那么我们求一个最小生成树最小化最大边权

    有两个限制的话我们先对(a)求出最小生成树,考虑把没有加入最小生成树的边加进去,显然会使得(1)(n)之间最大的(b)变小,就把剩下的边一条一条加进去,维护出(1)(n)之间的最大边权

    (lct)维护的是点的信息,处理边权的话我们不能像树剖那样把一条边的信息存在一个儿子里,因为树的结构时刻在变化,所以我们得把每一条边当成

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 1500005
    #define re register
    #define inf 999999999
    #define LL long long
    #define max std::max
    #define min std::min
    #define pt putchar(1)
    inline int read() {
        char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,m,ans;
    struct E{int u,v,a,b;} e[maxn];
    inline int cmp(E A,E B) {return A.a<B.a;}
    int ch[maxn][2],rev[maxn],fa[maxn],d[maxn],st[maxn];
    inline int nroot(int x) {return ch[fa[x]][1]==x||ch[fa[x]][0]==x;}
    inline void pushup(int x) {
        d[x]=x;
        if(e[d[x]].b<e[d[ch[x][0]]].b) d[x]=d[ch[x][0]];
        if(e[d[x]].b<e[d[ch[x][1]]].b) d[x]=d[ch[x][1]];
    }
    inline void pushdown(int x) {
        if(!rev[x]) return;
        rev[x]=0,rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
        if(ch[x][0]) std::swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
        if(ch[x][1]) std::swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
    }
    inline void rotate(int x) {
        int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][k^1];
        if(nroot(y)) ch[z][ch[z][1]==y]=x;
        ch[x][k^1]=y,ch[y][k]=w;
        pushup(y),pushup(x);fa[w]=y;fa[y]=x,fa[x]=z;
    }
    inline void splay(int x) {
        int y=x,top=0;
        st[++top]=x;
        while(nroot(y)) st[++top]=fa[y],y=fa[y];
        while(top) pushdown(st[top--]);
        while(nroot(x)) {
        	int y=fa[x];
            //printf("%d %d
    ",x,y);
            if(nroot(y)) rotate((ch[y][1]==x)^(ch[fa[y]][1]==y)?x:y);
            rotate(x);
        }
        //putchar(10);
    }
    inline void access(int x) {
        for(re int y=0;x;y=x,x=fa[x])
            splay(x),ch[x][1]=y,pushup(x);
    }
    inline void makeroot(int x) {
        access(x);splay(x);rev[x]^=1;std::swap(ch[x][0],ch[x][1]);
    }
    inline int findroot(int x) {
        access(x);splay(x);
        while(ch[x][0]) pushdown(x),x=ch[x][0];
        return x;
    }
    inline void split(int x,int y) {
        makeroot(x);access(y);splay(y);
    }
    inline void link(int x,int y) {
        makeroot(x);fa[x]=y;
    }
    inline void cut(int x,int y) {
        split(x,y);ch[y][0]=fa[x]=0,pushup(y);
    }
    int main()
    {
        n=read(),m=read();ans=inf;
        for(re int i=1;i<=m;i++) 
            e[i].u=read()+m,e[i].v=read()+m,e[i].a=read(),e[i].b=read();
        std::sort(e+1,e+m+1,cmp);
        for(re int i=1;i<=m;i++) {
            int x=e[i].u,y=e[i].v;
            if(findroot(x)!=findroot(y)) link(x,i),link(y,i);
                else {
                    split(x,y);int t=d[y];
                    if(e[i].b<e[d[y]].b) cut(e[t].u,t),cut(e[t].v,t),link(x,i),link(y,i);
                }
            if(findroot(m+1)==findroot(n+m)) 
                split(m+1,n+m),ans=min(ans,e[i].a+e[d[n+m]].b);
        }
        if(ans!=inf) printf("%d
    ",ans);else puts("-1");
        return 0;
    }
    
  • 相关阅读:
    centos 安装 TortoiseSVN svn 客户端
    linux 定时任务 日志记录
    centos6.5 安装PHP7.0支持nginx
    linux root 用户 定时任务添加
    composer 一些使用说明
    laravel cookie写入
    laravel composer 安装指定版本以及基本的配置
    mysql 删除重复记录语句
    linux php redis 扩展安装
    linux php 安装 memcache 扩展
  • 原文地址:https://www.cnblogs.com/asuldb/p/10383776.html
Copyright © 2011-2022 走看看