読者です 読者をやめる 読者になる 読者になる

srupのメモ帳

競プロで解いた問題や勉強したことを記録していくメモ帳

yukicoder No.59 鉄道の旅

問題

問題概要

区間の和と1つの要素に値を加算減算を拘束にできればいい.

解法

BITを使った. BITは
-区間の和
-1つ要素に値を加える
ことができるデータ構造.
今回の問題では積荷をBITで管理した. w>0の時はw以上の重さのものがk個より少なければ、その積荷を積むという処理をする.この時に、BITで管理していると、w以上のものの総和がlog(MAX_W)でもとまり、加算もlog(MAX_W)で行える。w<0の時はwがあれば-1を加算すればいい.
他の人と回答を見てると、omosa[i]などで重さiの荷物のものの個数などをメモしておくことで、sum(-w) - sum(-w - 1) = (重さwの荷物の数) の処理を代用している回答があった.

ミス

BITは実装が楽でいいですね.応用するのは難しそう. この問題はBIT使わずに、multiset使って、やっている人いたけど、TLEしてた。(n*logn)で通りそうなんだけどな.

コード

#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(n);i++)
//[1,n]
const int MAX_W = 1000010;
int bit[MAX_W + 1];

int sum(int i){//iまでの和を求める
    int s = 0;
    while(i > 0){
        s += bit[i];
        i -= i & -i;
    }
    return s;
}

void add(int i, int x){//iの値にxを加える
    while(i <= MAX_W){
        bit[i] += x;
        i += i & -i;
    }
}

int main(void){
    int n, k; cin >> n >> k;
    vector<int> w(n);
    rep(i, MAX_W + 1) bit[i] = 0;
    rep(i, n){
        int w; cin >> w;
        if(w > 0){
            if(sum(MAX_W) - sum(w - 1) < k){
                add(w, 1);
            }
        }else{
            if(sum(-w) - sum(-w - 1) >= 1){
                add(-w, -1);
            }
        }
    }
    cout << sum(MAX_W) << endl;
    return 0;
}