• [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;
    }
    
  • 相关阅读:
    Unity动态更换图片
    (特殊的)增删改查
    SQL Server 锁
    [转]排序规则
    [转]C#编写Windows服务程序图文教程
    [转]FreeTextBox使用详解 (版本3.1.1)
    [转]Newtonsoft.Json序列化和反序列
    C#性能优化实践(摘抄)
    一、PID控制原理
    POJ 2255已知二叉树前序中序求后序
  • 原文地址:https://www.cnblogs.com/asuldb/p/10383776.html
Copyright © 2020-2023  润新知