[BZOJ]3192: [JLOI2013]删除物品 树状数组

Description

箱子再分配问题需要解决如下问题:
(1)一共有N个物品,堆成M堆。
(2)所有物品都是一样的,但是它们有不同的优先级。
(3)你只能够移动某堆中位于顶端的物品。
(4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。

(5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。
(6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本:
不会有两个物品有着相同的优先级,且M=2

题解:

显然方案是唯一的,所以直接模拟即可。我们可以把两堆合并成为一个数组,每次找到次大和最大的之间的距离,就是把最大删掉的代价。可以用树状数组实现。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=100010;
int n1,n2,n=0,s[maxn],a[maxn],b[maxn];
void add(int x,int y){for(int i=x;i<=n;i+=(i&-i))s[i]+=y;}
int getsum(int x){int re=0;for(int i=x;i;i-=(i&-i))re+=s[i];return re;}
struct node{int id,x;}A[maxn];
bool cmp(node x,node y){return x.x>y.x;}
int c[maxn],pos[maxn];
int main()
{
    scanf("%d%d",&n1,&n2);
    for(int i=n1;i;i--)scanf("%d",&a[i]),A[++n].id=i,A[n].x=a[i];
    for(int i=1;i<=n2;i++)scanf("%d",&b[i]),A[++n].id=i+n1,A[n].x=b[i];
    sort(A+1,A+1+n,cmp);
    for(int i=1;i<=n;i++)c[A[i].id]=i,pos[i]=A[i].id;
    for(int i=1;i<=n;i++)s[i]=(i&-i);
    LL ans=0;
    pos[0]=n1;//pos[0]存的是栈顶 
    for(int i=1;i<=n;i++)
    {
        LL last=ans;
        int p2=pos[i-1],p1=pos[i];
        if(p1>p2)ans+=(LL)(getsum(p1-1)-getsum(p2));
        else ans+=(LL)(getsum(p2)-getsum(p1));
        add(pos[i],-1);
    }
    printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值