初次试探 - 可并堆☞左偏树

算法大意

左偏树中,每个节点被赋予了两个值,一个是他本身的value,另一个是他的深度(?可能不太恰当)dist,同过dist可以方便的实现两个堆的合并。
左偏树中,要求任何一个节点,其 leftson 的dist 值要大于其 rightson 的dist值,也就是说,左子树将会比右子树深(当然,这并不是堆的排序标准,堆顶元素究竟是什么要依据题目来定义大根堆还是小根堆,和优先队列是一样的,这里不再多说)
上面的定义请多读几遍,这段话虽然很短,但真正理解起来是有困难的。1. 一个左偏树把跟去掉以后,它的左儿子和右儿子各自也是一颗左偏树(精华所在)2. 整颗树虽然有可能会被卡成一条链,但其复杂度均摊下来每个操作都是log级别的。3. 删除和加入节点的方式不能用普通堆的手段了,因为那样会破坏dist数组,使得左偏性质遭到毁灭性打击。

可支持的操作

合并!这是最重要也是最基础的操作。
查询最大值(最小值)
删除最大值(最小值)(依赖于合并操作!)
插入节点(依赖于合并操作!)
(本篇博客只用到这么多)

合并: 将两个左偏树合并为一颗
这里使用 rs[ ],ls[ ],dist[ ],val[ ]分别表示右儿子,左儿子,深度,值。
样例为大根堆的合并操作:采用递归合并的思想(还记得前面的内容么,删掉任意节点后剩下的两个儿子仍为左偏树)

int merge(int x,int y){
    if(!x||!y)return x^y;//如果有一个子树为空,则返回另一个,另一种写法为return x|y;
    if(val[x] < val[y])swap(x,y);//保留较大的
    rs[x] = merge(rs[x] ,y);//保持左偏,右子树递归合并
    if(dist[rs[x]] > dist[ls[x]])swap(t[x].ls, t[x].rs);//保证左子树dist>右子树dist
    dist[x] = dist[rs[x]]+1;//根节点dist=右儿子dist + 1;
    return x;//合并后的根节点
}

代码其实相当短,但要想理解并熟练应用还要下工夫

有了这个合并操作,我们就可以做很多事情了;

想要插入一个值怎么办?
把这个值所对应的dist设为0,这样它就抽象为了只有一个节点的左偏树,然后直接merge一下即可。

想要删除根节点怎么办?

咱们不是有合并么,把根节点的左右儿子合并根节点不就没了么QAQ。

//吐槽一句,merge函数累不累啊。。。

顺便附上Luogu左偏树模板题的 AC 代码:

第一次的代码(写的比较丑)(啊哈哈哈左偏树我是一次AC的)

#include<bits/stdc++.h>

using namespace std;

const int N = 100010;

int fa[N];
int v[N],dist[N],ls[N],rs[N];
bool del[N];
int n,m;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}

int merge(int x,int y){
    if(!x||!y)return x|y;
    if(v[x]>v[y])swap(x,y);
    rs[x] = merge(rs[x] ,y);
    if(dist[rs[x]] > dist[ls[x]])swap(ls[x],rs[x]);
    dist[x] = dist[rs[x]]+1;
    return x;
}

void insert(int x,int y){
    x = find(x),y = find(y);
    if(x != y)fa[x] = fa[y] = merge(x , y);
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&v[i]);
        dist[i] = 0;
        fa[i] = i;
    }
    int op,x,y;
    while(m--){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d",&x,&y);
            if(del[x]||del[y])continue;
            insert(x,y);
        } else {
            scanf("%d",&x);
            if(del[x]){
                puts("-1");
            } else {
                x = find(x);
                cout<< v[x] <<endl;
                int ro = merge(rs[x],ls[x]);
                fa[x] = fa[ro] = ro;
                del[x] = true;
            }
        }
    }

}

用结构体来存储的代码(除了合并部分代码略有啰嗦其他还好)

#include<bits/stdc++.h>

using namespace std;

const int N = 100010;

int read(){
    int q=0;
    char c=getchar();
    while(c>'9'||c<'0')c=getchar();
    while(c>='0'&&c<='9')q=q*10+c-'0',c=getchar();
    return q ;
}

int n,m;
struct node{
    int val,dist,ls,rs;
}t[N];

bool del[N];
int fa[N];

int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}

int merge(int x,int y){
    if(!x||!y)return x^y;
    if(t[x].val > t[y].val)swap(x,y);
    t[x].rs = merge(t[x].rs ,y);
    if(t[t[x].rs].dist > t[t[x].ls].dist)swap(t[x].ls, t[x].rs);
    t[x].dist = t[t[x].rs].dist+1;
    return x;
}

int main(){
    n = read(); m = read();

    for(int i = 1;i <= n; i++){
        t[i].val = read();
        t[i].dist = 0;
        fa[i] = i;
    }

    int x,y,op;
    while(m--){
        op = read();
        if(op == 1){
            x = read(); y = read();
            if(del[x] || del[y])continue;
            x = find(x); y = find(y);
            if(x == y)continue;
            int ro = merge(x , y);
            fa[x] = fa[y] = ro;
        } else {
            x = read();
            if(del[x]){
                puts("-1");
            } else {
                x = find (x) ;
                printf("%d\n",t[x].val);
                int ro = merge(t[x].rs,t[x].ls);
                fa[x] = fa[ro] = ro;
                del[x] = true;
             }
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评标办法是指在项目招标或采购过程中,对投标方提交的文件和报价进行评审和比较,以确定最终中标者的一种方法。初次评审和最终评审是评标过程中的两个重要环节。 初次评审是在投标截止时间后,评标委员会对投标文件进行初步审核和筛选的过程。在初次评审中,评标委员会会对投标文件进行全面的审查,包括但不限于以下几个方面: 1. 投标文件的完整性:检查投标文件是否齐全、完整,是否包含了所有必要的文件和信息。 2. 技术能力和经验:评估投标方的技术能力、经验和专业资质,以确定其是否具备完成项目的能力。 3. 价格合理性:对投标方的报价进行评估,判断其是否合理、符合市场价格水平。 4. 合规性:检查投标文件是否符合招标文件中规定的要求和条件。 最终评审是在初次评审通过后,对初次评审合格的投标方进行深入比较和综合评估的过程。在最终评审中,评标委员会会根据招标文件中规定的评分标准和权重,对各个投标方进行打分和排名,以确定最终中标者。最终评审的主要内容包括但不限于以下几个方面: 1. 技术方案:评估投标方的技术方案是否切实可行、符合项目需求。 2. 经济条件:综合考虑投标方的报价、支付条件等经济因素。 3. 服务承诺:评估投标方对项目实施过程中的服务承诺和售后支持等方面的能力和承诺。 4. 综合评估:根据评分标准和权重,对各个投标方进行综合评估和比较,确定最终中标者。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值