左偏树/斜堆/可并堆-洛谷P3377 【模板】左偏树(可并堆)

https://www.luogu.org/problem/show?pid=3377
我们知道二叉堆,就是优先队列,那个stl有的,Priority Queues;
这个建议大家去试试手写;
我们知道二叉堆合并很难,时间复杂度高;
那我们怎么搞呢,用更高级的数据结构–可并堆;
先自学一下这个
http://wenku.baidu.com/search?word=%CB%E3%B7%A8%BA%CF%BC%AF%D6%AE%A1%B6%D7%F3%C6%AB%CA%F7%B5%C4%CC%D8%B5%E3%BC%B0%C6%E4%D3%A6%D3%C3%A1%B7&lm=0&od=0&fr=top_home
然后我就没什么好讲的了;
……
但是有些想法还是跟大家说说;
首先我们为什么要让这个堆左边偏大;
这个跟我们合并有关系;
合并时,我们把权值小的根节点的右儿子和权值大的更节点先合并;
所以我们让右边小一点合并速度更快;
对吧(对个屁)
那我们为什么要让 《权值小的根节点的右儿子去合并
而不是 《值大的根节点的右儿子去合并呢?;
因为根节点要最小呀!
那我们为什么是右节点合并而不是左合并,这样右节点深度会更小;
我们让右节点深度小,就是为了让右节点去合并,这样时间复杂度才可以保证啊;
那这时模版代码;
但是我的查询时间是O(log2n);
毕竟我们要找到根节点嘛;
当然可以用路径压缩;
这个是斜对

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct heap{
    int xx,yy,vv,fa,;
}a[100001];
bool b[100001];
int n,m,x,y,z;
int merge(int x,int y){
    if(!x)return y;
    if(!y)return x;
    if((a[x].vv>a[y].vv)||(a[x].vv==a[y].vv&&x>y))swap(x,y);
    int f=merge(a[x].yy,y);
    a[x].yy=a[x].xx;
    a[x].xx=f;
    return x;
}
void dfs(int x,int y){
    if(!x)return;
    a[x].fa=y;
    dfs(a[x].xx,y);
    dfs(a[x].yy,y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].vv),a[i].fa=i;
    while(m--){
        scanf("%d",&z);
        if(z==1){
            scanf("%d%d",&x,&y);
            if(b[x]||b[y])continue;
            int xx=a[x].fa;
            int yy=a[y].fa;
            if(xx==yy)continue;
            int f=merge(xx,yy);
            dfs(f,f);
        }else{
            scanf("%d",&x);
            if(b[x]){printf("-1\n");continue;}
            int xx=a[x].fa;
            b[xx]=1;
            printf("%d\n",a[xx].vv);
            int f=merge(a[xx].xx,a[xx].yy);
            dfs(f,f);
        }
    }
}

左偏树(跑得慢??????)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct heap{
    int xx,yy,vv,fa,dist;
}a[100001];
bool b[100001];
int n,m,x,y,z;
int merge(int x,int y){
    if(!x)return y;
    if(!y)return x;
    if((a[x].vv>a[y].vv)||(a[x].vv==a[y].vv&&x>y))swap(x,y);
    int f=merge(a[x].yy,y);
    a[x].yy=f;
    if(a[a[x].yy].dist>a[a[x].xx].dist)swap(a[x].xx,a[x].yy);
    a[x].dist=a[a[x].yy].dist+1;
    return x;
}
void dfs(int x,int y){
    if(!x)return;
    a[x].fa=y;
    dfs(a[x].xx,y);
    dfs(a[x].yy,y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].vv),a[i].fa=i;
    while(m--){
        scanf("%d",&z);
        if(z==1){
            scanf("%d%d",&x,&y);
            if(b[x]||b[y])continue;
            int xx=a[x].fa;
            int yy=a[y].fa;
            if(xx==yy)continue;
            int f=merge(xx,yy);
            dfs(f,f);
        }else{
            scanf("%d",&x);
            if(b[x]){printf("-1\n");continue;}
            int xx=a[x].fa;
            b[xx]=1;
            printf("%d\n",a[xx].vv);
            int f=merge(a[xx].xx,a[xx].yy);
            dfs(f,f);
        }
    }
}

路径压缩(无用,慢)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct heap{
    int xx,yy,vv,fa;
}a[100001];
bool b[100001];
int n,m,x,y,z;
int merge(int x,int y){
    if(!x)return y;
    if(!y)return x;
    if((a[x].vv>a[y].vv)||(a[x].vv==a[y].vv&&x>y))swap(x,y);
    a[x].yy=merge(a[x].yy,y);
    a[a[x].yy].fa=x;
    swap(a[x].yy,a[x].xx);
    return x;
}
int get(int x){while(a[x].fa!=x)x=a[x].fa;return x;}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].vv),a[i].fa=i;
    while(m--){
        scanf("%d",&z);
        if(z==1){
            scanf("%d%d",&x,&y);
            if(b[x]||b[y])continue;
            int xx=get(x);
            int yy=get(y);
            if(xx==yy)continue;
            int f=merge(xx,yy);
        }else{
            scanf("%d",&x);
            if(b[x]){printf("-1\n");continue;}
            int xx=get(x);
            b[xx]=1;
            printf("%d\n",a[xx].vv);
            a[xx].fa=merge(a[xx].xx,a[xx].yy);
            a[a[xx].fa].fa=a[xx].fa;
        }
    }
}
posted @ 2017-03-01 22:56  largecube233  阅读(146)  评论(0编辑  收藏  举报