Gym 102770 B-Bin Packing Problem 2020浙江省省赛 (线段树 + set)

在这里插入图片描述
题意:装箱问题。两种算法分别对应操作系统中的首次适应算法和最佳适应算法。然后给定你一个请求序列(顺序不可更改),然后问你在这两种不同的算法下,每种情况会各自申请多少个个大小为C的箱子?

思路:很明显就是想怎么用算法有优化这个两种模拟。

对于第一种操作:我们每次都需要找的是最前面的第一个大于当前ai的箱子,快速查询就那么几种方法,这里没有顺序,所以我们就有线段树维护区间最大值,然后既然要找最前面的,那么我每次就在符合条件的情况下,尽量往左子树走,否则才会往右子树去找。

第二种操作:每次找的是大于等于当前值的一个箱子,那我们就用一个set维护一下当前所有存在箱子的大小即可,如果当前都满足不了条件,再申请新的箱子。注意:因为箱子中可能出现重复的容量,所以我们这里用multiset不会自动去重的set维护。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int long long
const int MAXN = 1e6 + 7;
const int N = 1e6;
int tree[MAXN<<2],a[MAXN],b[MAXN],n,c,cnt;
multiset<int>st;
multiset<int>::iterator it;

void pushup(int rt){ tree[rt] = max(tree[rt<<1],tree[rt<<1|1]); }

void build(int rt,int l,int r){
	// tree[rt] = c;
	if(l == r){
		tree[rt] = c;
		return ;
	}
	int mid = (l+r)>>1;
	build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
	pushup(rt);
}

void modify(int rt,int l,int r,int p,int val){
	if(l == r){
		tree[rt] -= val;
		return ;
	}
	int mid = (l+r)>>1;
	if(p <= mid) modify(rt<<1,l,mid,p,val);
	else if(p > mid) modify(rt<<1|1,mid+1,r,p,val);
	pushup(rt);
}

int query(int rt,int l,int r,int val){
	if(l == r) return l;
	int mid = (l+r)>>1;
	int res;
	if(tree[rt<<1] >= val)
		res = query(rt<<1,l,mid,val);
	else if(tree[rt<<1|1] >= val)//这里初始化都为c 而题目又保证了ai < c 所以可以这样写
		res = query(rt<<1|1,mid+1,r,val);
	return res;
}

signed  main(){
	int t;
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&c);
		for(int i = 1;i <= n;i ++) scanf("%lld",&a[i]);
		build(1,1,n);
		cnt = 0;
		for(int i = 1;i <= n;i ++){
			int p = query(1,1,n,a[i]);
			if(p > cnt) cnt++;//查到的当前合法位置 大于cnt了 证明需要申请新的空间了。
			modify(1,1,n,p,a[i]);
		}
		int ans = 0;
		multiset<int> :: iterator it;
		st.insert(c - a[1]);
		for (int i = 2; i <= n; ++i) {
			it = st.lower_bound(a[i]);
			if (it == st.end()) {
				st.insert(c - a[i]);
				continue;
			}
			int v = *it - a[i];
			st.erase(it);
			st.insert(v);
		}
        printf("%lld %d\n",cnt,st.size());
        st.clear();
  	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值