Official
M - お片付け/Put Away Editorial
by
M - お片付け/Put Away Editorial
by
kyopro_friends
この問題は次のようなクエリ問題だと思うことができます。
数列 \(X\) が与えられる。次の \(2\) 種類のクエリを処理せよ:
- \(x\) が与えられる。\(X_i\geq x\) となる最小の \(i\) を求めよ
- \(i,x\) が与えられる。\(X_i\) を \(X_i-x\) に置き換えよ
ここで、1番目のクエリは次と同値になります。
- \(x\) が与えられる。\(\max_{j\leq i}X_j\) が \(x\) 以上となる最小の \(i\) を求めよ
このように読み替えることで、「\(\max_{j\leq i}X_j\) は \(x\) 以上か?」は \(i\) に関して単調になり、二分探索をすることができるようになります。したがって、これらのクエリは、区間maxを取得できるセグメントツリーを用いることで高速に処理できます。
元の問題を解く際の計算量はセグメントツリー上の二分探索の実装の仕方に依存し、\(O(N\log M)\) または \(O(N(\log M)^2)\) となります。
実装例(C++ with ACL)
#include<bits/stdc++.h>
#include<atcoder/segtree>
using namespace std;
using S=int;
S op(S x,S y){return max(x,y);}
S e(){return 0;}
int main(){
int n,m;
cin >> n >> m;
vector<int>nimotsu(n),hako(m);
for(int i=0;i<n;i++)cin >> nimotsu[i];
for(int i=0;i<m;i++)cin >> hako[i];
atcoder::segtree<S,op,e>seg(hako);
for(int i=0;i<n;i++){
auto f=[&](S x){return x<nimotsu[i];};
int r=seg.max_right<decltype(f)>(0,f);
if(r==m){
cout << "No\n" << i+1 << endl;
return 0;
}
seg.set(r,seg.get(r)-nimotsu[i]);
}
cout << "Yes" << endl;
for(int i=0;i<m;i++)cout << hako[i]-seg.get(i) << " ";
}
posted:
last update:
