题解:P13983 数列分块入门 8
ODT 入门。
我们考虑区间推平的总复杂度。
我们定义势能函数
对于 odt 的 split 操作,势能最多增加
这样我们就会得到一个性质:势能只有在减少时会计入时间复杂度中,所以对于一个数组而言,我们会有时间复杂度应为总势能与势能修改量的和:
然而 ODT 是带
#include<bits/stdc++.h>
using namespace std;
// warning! File IO!
struct node{
int l, r, val;
bool operator < (const node &x) const {
return l < x.l;
}
};
set<node>s;
int n;
auto split(int pos) {
if(pos > n) return s.end();
auto it = s.lower_bound({pos, 0, 0});
if(it != s.end() && it -> l == pos) return it;
it--;
int l = it-> l, r = it -> r, val = it -> val;
s.erase(it); s.insert({l, pos - 1, val});
return s.insert({pos, r, val}).first;
}
int assign(int l, int r, int v) {
int res = 0;
auto itr = split(r + 1), itl = split(l);
for(auto it = itl; it != itr; ++it)
if(it -> val == v) res += (it -> r - it -> l + 1);
s.erase(itl, itr);
s.insert({l, r, v});
return res;
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i++) {
int x; cin >> x; s.insert({i, i, x});
}
for(int i = 1; i <= n; i++) {
int l, r, v; cin >> l >> r >> v;
cout << assign(l, r, v) << '\n';
}
}
int main(){
int t = 1;
//cin >> t;
while(t--){
solve();
}
return 0;
}