zoukankan      html  css  js  c++  java
  • 堆的基本操作(手写模拟堆)

    地址:https://www.acwing.com/problem/content/841/

    解析:

    这个题比较麻烦的一点就是k。第k个插入的数,不是树里的序号。经过一系列变换后,第k个插入的数在树里的序号会发生交换。

    所以引入两个数组:ph[i]=x:表示第i次插入的数,在树中的序号为x。hp[i]=x:表示树中的序号i,是第x次插入的数。

    乍一看,hp[]似乎并没有什么用,每次交换h[]和ph[]即可了。别急,请看下面:

    我们来定义一个全新的交换方式:heap_swap(int u,int v)

    u,v做为树的两个结点号被传了进来。

    那么我们需要交换h[u],h[v],我们要交换两个ph[],但是,ph[]里的索引不知道,也就是说我们并不知道h[u],h[v]代表的数,是第几次插入的,自然就没法交换ph[]。

    这个时候就可以看出hp[]的厉害了,hp[u],hp[v]不就是表示第几次插入的数吗?也就是ph的索引,至此,就可以交换ph[]了。有代码:

    void heap_swap(int u,int v)
    {
        swap(h[u],h[v]);
        swap(ph[hp[u]],ph[hp[v]]);
        swap(hp[u],hp[v]);
    }

    可以发现,顺序对结果是没有影响的~

    关于堆,我有小笔记可供大家参考:https://www.cnblogs.com/liyexin/p/13942174.html

    这个是本题的一个难点,其他的就是模板了,看注释吧:

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #include<map>
    typedef long long ll;
    const int maxn=1e5+10;
    const int maxn2=3e6+10; 
    int hp[maxn],ph[maxn],h[maxn],n,m,siz;
    void heap_swap(int a,int b)
    {
        swap(h[a],h[b]);
        swap(ph[hp[a]],ph[hp[b]]);
        swap(hp[a],hp[b]);
    }
    void down(int u)
    {
        int t=u;
        if(u*2<=siz&&h[2*u]<h[t])
            t=2*u;
        if(2*u+1<=siz&&h[2*u+1]<h[t])
            t=2*u+1;
        if(u!=t)
        {
            heap_swap(u,t);
            down(t);
        }
    }
    void up(int u)
    {
        while(u/2>=1&&h[u/2]>h[u])
        {
            heap_swap(u/2,u);
            u=u/2;
        }
    }
    int main()
    {
        cin>>n;
        siz=0;//树的总大小
        m=0;//第几次插入
        while(n--)
        {
            char op[5];
            cin>>op;
            if(op[0]=='I')
            {
                int x;
                cin>>x;
                h[++siz]=x;//按照前面所说的,hp,ph的作用,进行值的更新
                ph[++m]=siz;
                hp[siz]=m;
                up(siz);//插到结尾,所以只需要up
            }
            else if(op[0]=='P')
            {
                cout<<h[1]<<endl;
            }
            else if(op[0]=='D'&&op[1]=='M')//删除最小
            {
                heap_swap(1,siz); //结尾覆盖上去,但是ph,hp会发生响应的改变,所以需要先进行连个值的交换,再down
                siz--;
                down(1);
            }
            else if(op[0]=='D')
            {
                int k;
                cin>>k;
                int u=ph[k];  //获取第k次插入的数在树中的下标
                heap_swap(u,siz);//删除,同样也可以先看成交换,再siz--
                siz--;
                up(u);
                down(u);
            }
            else
            {
                int k,x;
                cin>>k>>x;
                int u=ph[k];
                h[u]=x;
                down(u);
                up(u);
            }
        }
    }
  • 相关阅读:
    【刷题】AtCoder Regular Contest 002
    【刷题】AtCoder Regular Contest 001
    【刷题】LOJ 2863 「IOI2018」组合动作
    (栈)栈 给定push序列,判断给定序列是否是pop序列
    网易面试题:和为n连续正数序列
    Google面试题:计算从1到n的正数中1出现的次数
    递归法
    打印给定字符串中字符的所有排列
    C++ 实现不能被继承的类
    atoi 实现
  • 原文地址:https://www.cnblogs.com/liyexin/p/13942227.html
Copyright © 2011-2022 走看看