删除物品[JLOI2013]

——JLOI2013(bzoj3192)

删除物品

题目描述

箱子再分配问题需要解决如下问题:

(1)一共有N个物品,堆成M堆。

(2)所有物品都是一样的,但是它们有不同的优先级。

(3)你只能够移动某堆中位于顶端的物品。

(4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。

(5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。

(6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本: 不会有两个物品有着相同的优先级,且M=2

输入格式

第一行是包含两个整数N1,N2分别表示两堆物品的个数。接下来有N1行整数按照从顶到底的顺序分别给出了第一堆物品中的优先级,数字越大,优先级越高。再接下来的N2行按照同样的格式给出了第二堆物品的优先级。

输出格式

对于每个数据,请输出一个整数,即最小移动步数。

输入

3 3
1
4
5
2
7
3

输出

6

说明

$1<=N_1+N_2<=100000 $

解析

看完题应该有思路了,但纯模拟肯定是不行的,要用数据结构,用什么?

是的,确实用线段树/树状数组,但是用线段树统计啥?

这道题大体思路是这样的:将两堆物品头对头连起来,形成一列,想象中间有个挡板,移动物品相当于移动挡板。用0和1标记每个物品,表示这个物品取过还是没取过。移动挡板,扫过的0/1的和就是移动的步数对吧。把一个物品从1改成0是单点修改,统计扫过面积的和是区间查询,就用树状数组或线段树了。

我的代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100005;
typedef long long ll;
ll nn[maxn];
ll fake[maxn];
ll tree[maxn<<2];
ll lazy[maxn<<2];
int n1,n2;
struct seq
{
    int id,v;
};
seq num[maxn];
bool cmp(seq a,seq b)
{
    return a.v > b.v;
}
void pushup(int o)
{
    tree[o] = tree[o<<1] + tree[o<<1|1];
}
void build(int o,int l,int r)
{
    if(l == r)
    {
        tree[o] = nn[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
    pushup(o);
}
void modify(int pos,int w,int l,int r,int o)
{
    if(l == r)
    {
        tree[o] = w;
        return;
    }
    int mid = (l + r) >> 1;
    if(mid >= pos)
        modify(pos,w,l,mid,o<<1);
    else
        modify(pos,w,mid+1,r,o<<1|1);
    pushup(o);
}
void lazydown(int o,int ln,int rn)
{
    if(lazy[o] != 0)
    {
        lazy[o<<1] += lazy[o];
        lazy[o<<1|1] += lazy[o];
        tree[o<<1] += lazy[o] * ln;
        tree[o<<1|1] += lazy[o] * rn;
        lazy[o] = 0;
    }
}
int query(int L,int R,int l,int r,int o)
{
    if(L <= l && r <= R)
    {
        return tree[o];
    }
    int mid = (l + r) >> 1;
    lazydown(o,mid-l+1,r-mid);
    ll ans = 0;
    if(L <= mid)
        ans += query(L,R,l,mid,o<<1);  
    if(R > mid)
        ans += query(L,R,mid+1,r,o<<1|1);  
    return ans;
}
int main()
{
    ll ans = 0;
    scanf("%d%d",&n1,&n2);
    for(int i=1;i<=n1;i++)
        scanf("%lld",&fake[i]);
    reverse(fake+1,fake+n1+1);
    for(int i=n1+1;i<=n1+n2;i++)
        scanf("%lld",&fake[i]);
    for(int i=1;i<=n1+n2;i++)
    {
        num[i].id = i;
        num[i].v = fake[i];
    }
    memset(nn,1,n1+n2+1);
    int pointer = n1;
    for(int i=1;i<=n1+n2;i++)
        nn[i] = 1;
    build(1,1,n1+n2);
    sort(num+1,num+n1+n2+1,cmp);
    for(int i=1;i<=n1+n2;i++)
    {
        int p; bool mmp = 0;
        int temp = num[i].id;
        if(pointer > temp)
        {
            swap(pointer,temp);
            p = pointer - 1;
        }
        else
        {
            mmp = 1;
            p = pointer + 1;
        }
        modify(num[i].id,0,1,n1+n2,1);
        ans += query(pointer,temp,1,n1+n2,1);
        if(mmp == 1)
            pointer = temp;
    }
    printf("%lld",ans);
    return 0;
}

不要参考我的代码……我的代码样例没过,竟然就A了……

猜你喜欢

转载自www.cnblogs.com/Ch-someone/p/9478732.html