手搓堆

#include <iostream>
#include <algorithm>

using namespace std;
const int N = 1e5 + 10;
int h[N], ph[N], hp[N], cnt;  //h存值, ph存第k个插入的数对应的下标, hp存下标对应第几个插入的数

void heap_swap(int a, int b);
void down(int x);
void up(int x);
int main()
{
	int n, m = 0; cin >> n;
	while(n--)
	{
		string s; cin >> s;
		if(s == "I")  //插入--在堆尾插,cnt要加一,m也要加一,再up一下
		{
			int num; cin >> num;
			cnt++, m++;
			h[cnt] = num;
			ph[m] = cnt, hp[cnt] = m;
			up(cnt);
		}
		else if(s == "PM") cout << h[1] << endl;  //最小值--这是小根堆,所以堆顶就是最小值
		else if(s == "DM")  //删除最小值,将堆尾与堆顶交换,cnt减一,再down一下
		{
			heap_swap(1, cnt);
			cnt--;
			down(1);
		}
		else if(s == "D")  //删除任意值--将任意值与堆尾交换,cnt减一,若此位置的值变大则down,变小则up,两个都写,只会进行一个
		{
			int num; cin >> num;
			int k = ph[num];  //要先将对应的下标存起来,应为交换以后ph[num]就不是k了
			heap_swap(k, cnt);
			cnt--;
			up(k), down(k);
		}
		else if(s == "C")  //修改值--直接赋值,再up和down
		{
			int num, nu; cin >> num >> nu;
			int k = ph[num];  
			h[k] = nu;
			up(k), down(k);
		}
	}
}
void heap_swap(int a, int b)
{
	swap(h[a], h[b]);  //交换值
	swap(hp[a], hp[b]);  //交换下标对应第几个插入的数
	swap(ph[hp[a]], ph[hp[b]]);  //交换第几个插入的数对应的下标
	//并未交换下标,只是交换了下标的指向
}
void down(int x)
{
	int u = x;
	int l = u * 2, r = u * 2 + 1;
	if(l <= cnt && h[l] > h[u]) u = l;
	if(r <= cnt && h[r] > h[u]) u = r;
	if(u != x)
	{
		heap_swap(u, x);
		down(u);
	}
}
void up(int x)
{
	int u = x;
	while(u / 2 && h[u / 2] > h[u])
	{
		heap_swap(u / 2, u);
		u /= 2;
	}
}

stl

#include <iostream>
#include <vector>
#include <set>

using namespace std;
multiset<int> q;
const int N = 1e5 + 10;
int a[N];

int main()
{
    int n, m = 0; cin >> n;
    while(n--)
    {
        string s; cin >> s;
        if(s == "I")
        {
            int num; cin >> num;
            q.insert(num);
            a[++m] = num;
        }
        else if(s == "PM") cout << *q.begin() << endl;
        else if(s == "DM") q.erase(q.begin());
        else if(s == "D")
        {
            int num; cin >> num;
            if(q.find(a[num]) != q.end()) q.erase(q.find(a[num]));
        }
        else 
        {
            int k, x; cin >> k >> x;
            if(q.find(a[k]) != q.end()) q.erase(q.find(a[k]));
            a[k] = x;
            q.insert(x);
        }
    }
}

>1 【模板】堆

题目描述

给定一个数列,初始为空,请支持下面三种操作:

  1. 给定一个整数 \(x\),请将 \(x\) 加入到数列中。
  2. 输出数列中最小的数。
  3. 删除数列中最小的数(如果有多个数最小,只删除 \(1\) 个)。

输入格式

第一行是一个整数,表示操作的次数 \(n\)
接下来 \(n\) 行,每行表示一次操作。每行首先有一个整数 \(op\) 表示操作类型。

  • \(op = 1\),则后面有一个整数 \(x\),表示要将 \(x\) 加入数列。
  • \(op = 2\),则表示要求输出数列中的最小数。
  • \(op = 3\),则表示删除数列中的最小数。如果有多个数最小,只删除 \(1\) 个。

输出格式

对于每个操作 \(2\),输出一行一个整数表示答案。

样例

5
1 2
1 5
2
3
2
2
5

提示

对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 10^6\)\(1 \leq x \lt 2^{31}\)\(op \in \{1, 2, 3\}\)

代码

#include <iostream>
#include <set>

using namespace std;
multiset<int> q;
const int N = 1e6 + 10;
int a[N], cnt;

int main()
{
	int n, m = 0; cin >> n;
	while(n--)
	{
		int op; cin >> op;
		if(op == 1)
		{
			int num; cin >> num;
			q.insert(num);
			m++;
			a[m] = num;
		}
		else if(op == 2) cout << *q.begin() << endl;
		else q.erase(q.begin());
	}
}

>2 为大猩猩拍照

题目

https://codeforces.com/contest/2000/problem/E

思路

计算移动正方形时每个格子重复了几次--二维数组差分和前缀和
将最大高度的猩猩放在重复次数最多的格子--用大根堆弹出最大值,cnt--,最大值和当前最大高度相乘

代码

#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>

using namespace std;
typedef long long ll;

bool cmp(int a, int b);
int main()
{
	int t; cin >> t;
	while(t--)
	{
		int n, m, k; cin >> n >> m >> k;
		vector<vector<ll>> a(n + 10, vector<ll>(m + 10));
		for(int i = 1; i <= n - k + 1; i++)
		{
			for(int j = 1; j <= m - k + 1; j++)
			{
				a[i][j] += 1;
				a[i + k][j + k] += 1;
				a[i + k][j] -= 1;
				a[i][j + k] -= 1;
			}
		}
		multiset<ll> q;
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= m; j++)
			{
				a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
				q.insert(a[i][j]);
			}
		}
		int w; cin >> w;
		vector<int> b(w + 10);
		for(int i = 1; i <= w; i++) cin >> b[i];
		sort(b.begin() + 1, b.end(), cmp);
		ll sum = 0;
		for(int i = 1; i <= w; i++) 
		{
			sum += b[i] * (*q.rbegin());
			q.erase(--q.end());
		}
		cout << sum << endl;
	}
}
bool cmp(int a, int b)
{
	return a > b;
}
posted @ 2024-11-29 23:55  PeachyGalaxy  阅读(11)  评论(0编辑  收藏  举报