Official
E - 本棚の整理 / Organizing the Bookshelf Editorial
by
E - 本棚の整理 / Organizing the Bookshelf Editorial
by
kyopro_friends
取り除かれた本を詰めないことで、「残っている本のうち左から \(T\) 番目は元々何番目の本か?」を高速に判定することができればよいです。
「元々 \(i\) 番目の本がまだ本棚に残っていれば \(1\) 、取り除かれていれば \(0\) 」となる配列 \(F_i\) を考えます。このとき元々 \(i\) 番目の本は、いま本棚にある本のうち左から \(\sum_{j=1}^{i}F_i\) 番目となります。よって逆にいま本棚になる本のうち左から \(x\)番目の本が元々何番目であるかは、 \(F\) の累積和の二分探索により求めることができます。
\(1\) 回の操作では \(F\) の高々 \(1\) 箇所のが更新されるため、 1点更新・区間和取得が高速に行えるデータ構造で \(F\) を管理すればよく、セグメントツリーにより実現できます。
実装例 (C++)
#include<bits/stdc++.h>
#include<atcoder/segtree>
using namespace std;
int e(){return 0;}
int op(int x, int y){return x + y;}
int main(){
int n, q;
cin >> n >> q;
vector<int>d(n);
for(int i=0; i<n; i++) cin >> d[i];
atcoder::segtree<int, op, e>seg(vector<int>(n, 1));
for(int i=0; i<q; i++){
int t;
cin >> t;
auto f = [&](int x){return x < t;};
int r = seg.max_right(0, f);
if(r != n){
d[r]--;
if(d[r] == 0){
seg.set(r, 0);
}
}
cout << seg.all_prod() << endl;
}
}
実装例 (Python)
from atcoder.segtree import SegTree
from operator import add
N, Q = map(int, input().split())
D = list(map(int, input().split()))
seg = SegTree(add, 0, [1]*N)
for _ in range(Q):
T = int(input())
def f(x):
return x < T
r = seg.max_right(0, f)
if r != N:
D[r] -= 1
if D[r] == 0:
seg.set(r, 0)
print(seg.all_prod())
posted:
last update:
