2020浙江省赛ZJCPC B.Bin Packing Problem (线段树+map)

原题链接


题意:按顺序(记住放入物品的顺序是给定的)给一串序列,代表物品的重量,并且给定容器的容量大小, 要求最少需要几个容器存放这些物品。
题中给了两种算法:

  1. 从前往后遍历容器,找到第一个可以放的容器,把物品放进去,如果放不了,再开一个位置
  2. 找到能放并且当前剩余容量最小的容器,如果放不下,再开一个位置

第一个算法按照朴素算法,需要n2的复杂度。但我们可以考虑维护区间的最值,如果可以往左找就一直往左,直到找到。因此可以考虑线段树,我们维护区间的最值,初始值全部赋值为容量,如果当前放的物品体积小于左子树的最大值,那么可以往左子树递归,否则向右递归。

第二个算法是最优原则,题解所给的做法是利用set,但我一直被卡,所以尝试用map基于红黑树的原理来查找,记住查找时用map自带的lower_bound,效率可以提升很多。

附上ac代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <map>
using namespace std;
//#define ACM_LOCAL
typedef long long ll;
typedef long double ld;
typedef pair<int, int> PII;
const int N = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int a[N];
int n, c, T;
struct node {
    
    
    int l, r;
    int maxx;
    int tag;
}t[N<<2];

void push_up(int u) {
    
    
    t[u].maxx = max(t[u<<1].maxx, t[u<<1|1].maxx);
}

void push_down(int u) {
    
    
    if (t[u].tag != 0) {
    
    
        t[u<<1].tag = t[u].tag;
        t[u<<1|1].tag = t[u].tag;
        t[u<<1].maxx += t[u].tag;
        t[u<<1|1].maxx += t[u].tag;
        t[u].tag = 0;
    }
}

void build(int l, int r, int u) {
    
    
    t[u].l = l, t[u].r = r;
    t[u].maxx = c;
    t[u].tag = 0;
    if (t[u].l == t[u].r) {
    
    
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, u<<1);
    build(mid+1, r, u<<1|1);
    push_up(u);
}

void update(int pos, int u, int v) {
    
    
    if (t[u].l == t[u].r) {
    
    
        t[u].maxx += v;
        t[u].tag += v;
        return;
    }
    push_down(u);
    int mid = (t[u].l + t[u].r) >> 1;
    if (pos <= mid) update(pos, u<<1, v);
    else update(pos, u<<1|1, v);
    push_up(u);
}

int query(int val, int u) {
    
    
    if (t[u].l == t[u].r) {
    
    
        return t[u].l;
    }
    push_down(u);
    if (val <= t[u<<1].maxx) return query(val, u<<1);
    else return query(val, u<<1|1);
}

void solve () {
    
    
    scanf("%d", &T);
    while (T--) {
    
    
        scanf("%d %d", &n, &c);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        build(1, n, 1);
        int Max_bot = 0;
        for (int i = 1; i <= n; i++) {
    
    
            int pos = query(a[i], 1);
            Max_bot = max(Max_bot, pos);
            update(pos, 1, -a[i]);
        }
        map<int, int> mp;
        mp[c] = 1;
        for (int i = 1; i <= n; i++) {
    
    
            auto it = mp.lower_bound(a[i]);
            if (it == mp.end()) {
    
    
                mp[c-a[i]]++;
            }
            else {
    
    
                mp[it->first - a[i]] ++;
                mp[it->first]--;
                if (mp[it->first] == 0) mp.erase(it);
            }
        }
        int Max_bot_2 = 0;
        for (auto x : mp) Max_bot_2 += x.second;
        
        printf("%d %d\n", Max_bot, Max_bot_2);
    }
}
int main() {
    
    
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

猜你喜欢

转载自blog.csdn.net/kaka03200/article/details/109242321