4234最小差值生成树

有点巧妙啊!

s[x]每次维护的是最小值

我们将边按从大到小排个序,这样编号小的就在前面啦!QAQ

再按最小生成树的LCT的做法来

不过我们每次要用一个book标记前面最小边的编号

每次要更新答案时,一直往前跳,跳到最晚更新的即使最小的

我口胡的,错了请dalao指出

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MN 700005
#define re register int
#define ll long long
using namespace std;
int f[MN],v[MN],s[MN],r[MN],son[MN][2];
int zhan[MN];
int n,m,cnt;
int book[MN];
int ltk;
struct tu{
    int u,v,w;
}e[MN];
bool comp(tu p,tu q){
    return p.w<q.w;
}
int get(int x){////判断节点是否为一个Splay的根(与普通Splay的区别1)
    return son[f[x]][0]==x||son[f[x]][1]==x;
}////如果连的是轻边,他的父亲的儿子里没有它
void pushup(int x){
    s[x]=x;
    if(s[son[x][0]]> n && (s[x]<= n ||s[x]>s[son[x][0]] ) ) s[x]=s[son[x][0]];
    if(s[son[x][1]]> n && (s[x]<= n ||s[x]>s[son[x][1]] ) ) s[x]=s[son[x][1]];
}
void filp(int x){
    swap(son[x][0],son[x][1]);
    r[x]^=1;
}
void pushdown(int x){
    if(!r[x])return;
    r[x]=0;
    if(son[x][0])filp(son[x][0]);
    if(son[x][1])filp(son[x][1]);
}
void rotate(int x){
    int y=f[x],z=f[y],k=(son[y][1]==x),s=son[x][!k];
    if(get(y))son[z][son[z][1]==y]=x;son[x][!k]=y;son[y][k]=s;
    if(s)f[s]=y;f[y]=x;f[x]=z;
    pushup(y);
}
void splay(int x){
    int y=x,top=0;
    zhan[++top]=y;
    while(get(y))zhan[++top]=f[y],y=f[y];
    while(top)pushdown(zhan[top--]);
    while(get(x)){
        y=f[x],top=f[y];
        if(get(y))
        rotate((son[y][0]==x)^(son[top][0]==y)?x:y);
        rotate(x);
    }
    pushup(x);
    return;
}
void access(int x){
    for(re y=0;x;y=x,x=f[x]){
    splay(x);
    son[x][1]=y;
    pushup(x);
    }
}
void makeroot(int x){
    access(x);
    splay(x);
    filp(x);
}
int findroot(int x){    
    access(x);
    splay(x);
    while(son[x][0])pushdown(x),x=son[x][0];
    splay(x);
    return x;
}
void split(int x,int y){
    makeroot(x);
    access(y);
    splay(y);
}
void link(int x,int y){
    makeroot(x);
    if(findroot(y)!=x)f[x]=y;
}
void cut(int x){
//对cut进行%改
    splay(x);
    f[son[x][0]]=f[son[x][1]]=0;
}
int main(){
    scanf("%d%d",&n,&m);
    int pos=1;
    int ans=0x7fffffff;
    int now=0;
    for(re i=1;i<=m;i++)
    {
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    }
    sort(e+1,e+1+m,comp);
    for(re i=1;i<=m;i++){
        int x=e[i].u,y=e[i].v;
        if(x==y){book[i]=1;continue;}
        makeroot(x);
        if(findroot(y)!=x)link(e[i].u,i+n),link(i+n,e[i].v),++ltk;
        else{        
            split(x,y);
            now=s[y];
            book[now-n]=1;
            cut(now);
            link(x,n+i);
            link(n+i,y);
        }
        while(book[pos]&&pos<=i)++pos;
        if(ltk>=n-1)ans=min(ans,e[i].w-e[pos].w);
}
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-07-21 11:24  红色OI再临  阅读(178)  评论(0编辑  收藏  举报