BZOJ3192: [JLOI2013]刪除物品 樹狀數組

BZOJ 3192: [JLOI2013]刪除物品

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 877  Solved: 511

題解:
把第一堆n1個數倒過來形成一個數組,和n2拼接起來
比如樣例按照上述方法就是:5 4 1 2 7 3
維護一個樹狀數組長度爲n+m,剛開始所有點的權值均爲1,每次查詢當前最大值和次大值之間的區間和,然後把當前最大值的地方設成0就OK
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,c[N];
long long ans;
struct pp{int v,pos;}a[N];
bool cmp(pp u,pp v){return u.v>v.v;}
int Query(int x)
{
	int tmp=0;
	for(;x;x-=(x&-x)) tmp+=c[x];
	return tmp;
}
void Modify(int x,int v)
{
	for(;x<=n+m;x+=(x&-x)) c[x]+=v;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=n;i>=1;i--) scanf("%d",&a[i].v),a[i].pos=i;
	for(int i=n+1;i<=n+m;i++) scanf("%d",&a[i].v),a[i].pos=i;
	sort(a+1,a+n+m+1,cmp);
	if(a[1].pos>n) a[0].pos=n;
	else a[0].pos=n+1;
	for(int i=1;i<=n+m;i++) c[i]=(i&-i);
	for(int i=1;i<=n+m;i++)
	{
		int l=a[i-1].pos,r=a[i].pos;
		if(l>r) swap(l,r);
		ans+=Query(r-1)-Query(l);
		Modify(a[i].pos,-1);
	}
	printf("%lld",ans);
} 


Description

 
箱子再分配問題需要解決如下問題:
 (1)一共有N個物品,堆成M堆。
 (2)所有物品都是一樣的,但是它們有不同的優先級。
 (3)你只能夠移動某堆中位於頂端的物品。
 (4)你可以把任意一堆中位於頂端的物品移動到其它某堆的頂端。若此物品是當前所有物品中優先級最高的,可以直接將之刪除而不用移動。
 
(5)求出將所有物品刪除所需的最小步數。刪除操作不計入步數之中。
 (6)只是一個比較難解決的問題,這裏你只需要解決一個比較簡單的版本:
         不會有兩個物品有着相同的優先級,且M=2
 

Input

第一行是包含兩個整數N1,N2分別表示兩堆物品的個數。
接下來有N1行整數按照從頂到底的順序分別給出了第一堆物品中的優先級,數字越大,優先級越高。
再接下來的N2行按照同樣的格式給出了第二堆物品的優先級。
 

Output

對於每個數據,請輸出一個整數,即最小移動步數。
 

Sample Input

3 3
1
4
5
2
7
3

Sample Output

6

HINT

1<=N1+N2<=100000

Source

[Submit][Status][Discuss]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章