——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了……