C - Upgrade Required Editorial
by
physics0523
データ構造を利用して、いわゆる「殴る」解法をいくつか紹介します。
multiset を用いてシミュレートする方法
pair<バージョン, 台数> を multiset で管理しながらシミュレートすることでこの問題に正解できます。
実装例について、時間計算量は \(O((N+Q) \log (N+Q))\) です。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
using pi=pair<int,int>;
int main(){
int n,q;
cin >> n >> q;
multiset<pi> st;
for(int i=1;i<=n;i++){
st.insert({i,1});
}
while(q--){
int x,y;
cin >> x >> y;
int res=0;
while(!st.empty()){
auto it=st.begin();
if((*it).first>x){break;}
res+=(*it).second;
st.erase(it);
}
if(st.size()>0){ st.insert({y,res}); }
cout << res << "\n";
}
return 0;
}
note: このコード中の multiset を set にすると WA になります。何故でしょうか?
priority_queue を利用する方法
シミュレートに priority_queue を利用しても構いません。
実装例について、時間計算量は \(O((N+Q) \log (N+Q))\) です。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
using pi=pair<int,int>;
int main(){
int n,q;
cin >> n >> q;
priority_queue<pi,vector<pi>,greater<pi>> pq;
for(int i=1;i<=n;i++){
pq.push({i,1});
}
while(q--){
int x,y;
cin >> x >> y;
int res=0;
while(!pq.empty()){
if(pq.top().first>x){break;}
res+=pq.top().second; pq.pop();
}
if(res>0){ pq.push({y,res}); }
cout << res << "\n";
}
return 0;
}
lazy_segtree を利用する方法
ACL にも含まれる、 lazy_segtree (遅延伝播セグメント木) を利用することでもこの問題に正解できます。
実装例について、時間計算量は \(O((N+Q) \log N)\) です。
実装例 (C++):
#include<bits/stdc++.h>
#include<atcoder/lazysegtree>
using namespace std;
using namespace atcoder;
using ll=long long;
struct S{
ll val,len;
};
using F=ll;
const F ID=8e18;
S op(S a,S b){ return {a.val+b.val,a.len+b.len}; }
S e(){ return {0,0}; }
S mapping(F f,S x){
if(f!=ID){ x.val=f*x.len; }
return x;
}
F composition(F f,F g){ return (f==ID)?g:f; }
F id(){ return ID; }
int main(){
ll n,q;
cin >> n >> q;
vector<S> v(n+1,{1,1});
v[0]={0,1};
lazy_segtree<S, op, e, F, mapping, composition, id> seg(v);
while(q--){
ll x,y;
cin >> x >> y;
ll res=seg.prod(0,x+1).val;
seg.apply(0,x+1,0);
seg.set(y,{seg.get(y).val+res,1});
cout << res << "\n";
}
return 0;
}
posted:
last update:
