[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\n",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\n",ans);else puts("-1");
    return 0;
}
posted @ 2019-02-15 15:07  asuldb  阅读(175)  评论(0编辑  收藏  举报