CF R631 div2 1330 E Drazil Likes Heap

LINK:Drazil Likes Heap

那天打CF的时候 开场A读不懂题 B码了30min才过(当时我怀疑B我写的过于繁琐了。

C比B简单多了 随便yy了一个构造发现是对的。D也超级简单 dp了一下就没了。

但是到E就只剩下30min(都怪A B浪费我过多时间。

观察题目中给的一个程序 其维护了一个大根堆且这个程序意思是一个函数

这个函数是指对于这个大根堆上的一个非空节点来说每次会将这个值给删掉继承最大的儿子值 然后递归值最大的儿子值得某个节点没有一个非空儿子(那么这个点的值被删掉为0.

题目想让我们进行K次操作 每次操作都进行调用一次f函数 并且K次操作后保证是一个二叉树 并且维护二叉树的形态。

看起来很复杂 但其实发现在某个点x删除 比在x的儿子处删除要优 且x的删除对x的整棵总删除次数没有任何影响。

而且可以证明 光删父亲比两个儿子组合删最后删一次父亲不会更差。所以就不存在先删小的会比先删大的要优了。

所以这是一个裸的贪心 我们直接按照下标贪心的删除即可。考虑到什么时候不能删?每次我们删除某个节点的时候可以提前知道删除的会是哪个位置以此来判断即可。

删完一个节点后 位置的更新由于是二叉树所以为logn的高度 总复杂度nlogn.值得注意删除的过程其实我们在手写大根堆。

const int MAXN=2100000;
int T,n,m,maxx,top;ll cnt;
int a[MAXN],pos[MAXN],d[MAXN],ans[MAXN];
inline void gx(int x)
{
	if(!a[x<<1]&&!a[x<<1|1])pos[x]=x;
	else
	{
		if(a[x<<1]>a[x<<1|1])pos[x]=pos[x<<1];
		else pos[x]=pos[x<<1|1];
	}
}
inline void del(int x)
{
	if(pos[x]==x){a[x]=0;return;}
	if(a[x<<1]>a[x<<1|1])a[x]=a[x<<1],del(x<<1);
	else a[x]=a[x<<1|1],del(x<<1|1);
	gx(x);
}
int main()
{
	freopen("1.in","r",stdin);
	get(T);
	while(T--)
	{
		get(n);get(m);
		maxx=(1<<n)-1;cnt=top=0;
		rep(1,maxx,i)get(a[i]),d[i]=d[i>>1]+1,cnt+=a[i];
		rep(maxx+1,(1<<(n+1))-1,i)a[i]=0;
		fep(maxx,1,i)gx(i);
		int ww=(1<<m)-1;
		rep(1,ww,i)
		{
			while(d[pos[i]]>m)
			{
				ans[++top]=i;
				cnt-=a[i];
				del(i);
			}
		}
		putl(cnt);
		rep(1,top,i)printf("%d ",ans[i]);
		if(T)puts("");
	}
	return 0;
}

原文地址:https://www.cnblogs.com/chdy/p/12643819.html

时间: 2024-07-30 22:07:05

CF R631 div2 1330 E Drazil Likes Heap的相关文章

Codeforces 631 (Div. 2) E. Drazil Likes Heap 贪心

https://codeforces.com/contest/1330/problem/E 有一个高度为h的大顶堆:有2h -1个不同的正整数,下标从1到2h−1,1<i<2h, a[i]<a[⌊i/2⌋]. 现在我们要降低堆的高度,为h,有2g-1个整数,那么我们要删掉2h-2g个数: 选择索引 i 删除,删除方法如下: 被删除的节点值为0,代表该节点不存在. 所以操作后,2g-1个元素的下标在[1,2g-1]范围内:使得剩余元素的总和最小,并且输出调用删除函数时删除的节点下标. 人话

CF #261 div2 D. Pashmak and Parmida&amp;#39;s problem (树状数组版)

Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partner to be clever too (although he's not)! Parmida has prepared the following test problem for Pashmak. There is a sequence a that consists of n

CF #261 DIV2 A,B,C,D

A 先判断邻边长度是否相等,不是就无法构成正方形,否则的话位置坐标搞一下 #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <algorithm> #include <bitset> #include <vector> #include <set>

CF#215 DIV2: B. Sereja and Suffixes

Sereja has an array a, consisting of n integers a1, a2, ..., an. The boy cannot sit and do nothing, he decided to study an array. Sereja took a piece of paper and wrote out m integers l1,?l2,?...,?lm (1?≤?li?≤?n). For each number li he wants to know

cf#261 div2 解题报告

.....代码没什么可说的,主要是学习各路大神姿势 A题 化简化简水题,都告诉平行坐标轴了,数据还出了对角线,后面两个点坐标给的范围也不错 ........和最优代码相比姿势有点混乱 #include <cstdio> int x[4],y[4]; int abs(int n){ return n<0?-n:n; } int main(){ scanf("%d%d%d%d",x,y,x+1,y+1); int dx=abs(x[0]-x[1]); int dy=abs

cf 301 div2

A - Combination Lock 题目大意:给有n个(0-9)环圈密码锁,数串 s1->s2最少移动次数: 题目分析: 简单模拟: 代码: const int N=100007; char s1[N],s2[N]; int main() { int n; while(scanf("%d",&n)==1) { int ans=0; scanf("%s%s",s1+1,s2+1); for(int i=1;i<=n;i++) { int a=

CF #488 Div2

A 模拟 #include <bits/stdc++.h> using namespace std; int a[100]; int main() { int n, m; scanf("%d %d", &n, &m); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } int mask = 0; for (int i = 0; i < m; i++) { int x

CF 313 DIV2 B 树状数组

http://codeforces.com/contest/313/problem/B 题目大意 给一个区间,问你这个区间里面有几个连续相同的字符. 思路: 表示个人用树状数组来写的...了解了树状数组的本质就行了. 当然用sum[r]-sum[l]也是可以的

CF #327 DIV2 D、E

两题都不难. 对于D题,可以使用相对移动,把吹aircraft移动变成相反方向的待援点的移动.假设此时时间为t,把aircraft的速度设为Vmax,看待援点在飞船最大速度飞行t秒的范围内,注意风向变化的时间点即可.其实很明显的二分.. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7