P3253 [JLOI2013]删除物品

题意:

给你了两个堆,你可以随便选择一个堆顶的元素,将它放在另外一个堆上面,如果堆顶的元素的优先级是所有元素中的最大的,那么我们就可以将它删除,问你最少需要多少步能够将所有的元素删除。

思路

我们将两个堆按照堆顶合并起来,假如给你的两个堆分别是(从堆顶到堆底)1、4、5。2、7、3,合并之后是:5、4、1、2、7、3。这样我们可以看成一个数组,但是其实位置该怎样判断呢,我们可以在两个堆顶之间加一个元素,标记为起点,就是5、4、1、0、2、7、3。这样我们可以从0这个位置开始进行寻找,那么现在数组的长度是7,我们标记一下我们的起点位置s = 4(就是0这个位置),然后这个时候我们只需要寻找最大值,次大值,次次大值…即可。
我们现在来拟一下这个操作过程:首先我们需要一个数组来记录出现的这些数以及他们的顺序,在这个过程中就add,因为在后面我们要算当前位置和下个最大值之间的距离,并且我们是从最大值开始寻找的,所以这里得到的数组我们需要从大到小进行排序,后面直接遍历即可。
我们在来想一下遍历的过程,我们是从大到小的顺序来遍历的,我们要找这个最大值的位置,那么我们在输入的时候还需要记录每一个值的id,先来看一下代码:

#include <bits/stdc++.h>

#define int long long

using namespace std;

const int N = 1e5 + 10;

int n, m;
int tr[N];

struct node
{
    int idx, val;
    bool operator < (const node &t) { return val > t.val;}
}a[N];

int lowbit(int x) { return x & -x; }

void add(int x, int k) { for (int i = x; i <= m + n + 1; i += lowbit(i)) tr[i] += k; }

int sum(int x)
{
    int sum = 0;
    for (int i = x; i; i -= lowbit(i)) sum += tr[i];
    return sum;
}

signed main()
{
    std::ios::sync_with_stdio(false);

    cin >> n >> m;
    for (int i = n; i >= 1; i --) { cin >> a[i].val; a[i].idx = i; add(i, 1); }
    for (int i = n + 2; i <= n + m + 1; i ++) { cin >> a[i].val; a[i].idx = i; add(i, 1); }

    sort(a + 1, a + n + m + 2);

    int ans = 0;
    int top = n + 1;
    for (int i = 1; i <= n + m; i ++)
    {
        int cur = a[i].idx;
        if (top < cur) { ans += sum(cur - 1) - sum(top); top = cur - 1; add(cur, -1); }
        else { ans += sum(top) - sum(cur); top = cur; add(cur, -1); }
    }

    cout << ans << endl;

    return 0;
}

现在来解释一下循环中的if else的原因:
我们要考虑指针位置和当前最大值的位置情况:
1.假如指针在当前最大值的左边:# # # 0 # m # (0表示指针的位置,m表示当前最大值的位置),那么我们知道此时只需要移动一个数字,然后就可以将最大值删除掉,所以我们要找的是sum(m-1),而不是sum(m),因为我们只需要算他们之间隔了多少个。
2.假如指针在当前最大值的右边:# m # # # 0 #,我们可以看出来它们之间需要移动三个单位,移动了之后最大值就暴露出来了,就可以直接删除了,所以是sum(top) - sum(cur)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值