Codeforces 1329 C Drazil Likes Heap —— 暴力,一丢丢想法

This way

题意:

现在有一个高度为h的满二叉大顶堆。每个点的值都是不一样的。你要缩小这个堆到高度为g,并且这个二叉堆依旧是满的。每次你选择一个点i,执行以下操作:
在这里插入图片描述
然后a[x]=0表示点x已被删除。
让你构造一个i的序列使得最后这个二叉堆的所有节点的值的和最小。问你这个和以及删除的序列。

题解:

初始化的顺序错了,,一直T。
那么你构造序列的时候其实就相当于删除了当前点的值,并且从这个点到叶子结点的贪心最大路径上的值往上移一格。所以这题可以贪心做。
那么由于它是二差大顶堆,而高度最大是20,那么我们可以暴力从大到小枚举要删的值是什么。然后查看这个值是否可以删除,怎么查看,执行图中操作,找到最下面的点,查看这个点的高度是否为g,如果是的话就不能再删了。此时,这个高度为g直到根节点的这些点的值都不能在被选择。因为如果选了这些点,那么就会查到这个点。如果这个节点可以被删除,那么再从选择的值开始做一遍图中的操作即可。
siz数组好像其实并没有什么用
dep数组表示当前点的深度
pos[x]表示值x所在的位置是什么
vis数组表示当前点是否可以被选

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e6+5;
int a[N*2],b[N],dep[N],siz[N],n,m,pos[N],vis[N];
vector<int>vec;
int p;
int del(int x){
    int now=x,f=0;
    while(a[now]){
        if(a[now<<1]<a[now<<1|1])
            now=now<<1|1;
        else
            now=now<<1;
    }
    now>>=1;
    p=now;
    if(dep[now]==m&&siz[now]==1)
        return 0;
    while(p)
        siz[p]--,p>>=1;
    while(a[x]){
        if(a[x<<1]<a[x<<1|1])
            a[x]=a[x<<1|1],pos[a[x]]=x,x=x<<1|1;
        else
            a[x]=a[x<<1],pos[a[x]]=x,x=x<<1;
    }
    return 1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        vec.clear();
        scanf("%d%d",&n,&m);
        ll sum=0;
        for(int i=1;i<(1<<n);i++){
            scanf("%d",&a[i]),b[i]=a[i];
            sum+=a[i];
            pos[a[i]]=i;
            dep[i]=log2(i)+1+1e-6;
            siz[i]=(1<<(n-dep[i]+1))-1;
        }
        sort(b+1,b+1+(1<<n)-1);
        int res=1<<n;
        res--;
        int num=res;
        while(res>=(1<<m)){
            int ans=pos[b[num]];
            while(!del(pos[b[num]])){
                while(p)
                    vis[a[p]]=1,p>>=1;
                num--;
                while(vis[b[num]])
                    num--;
                ans=pos[b[num]];
            }
            vec.push_back(ans);
            sum-=b[num--];
            res--;
        }
        printf("%lld\n",sum);
        for(auto i:vec)
            printf("%d ",i);
        printf("\n");
        for(int i=1;i<(1<<n);i++)vis[a[i]]=0,a[i]=0;
    }
    return 0;
}
发布了584 篇原创文章 · 获赞 33 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/105346703