Rotated Inversions
这个绝对比 E 简单。
对于 ,是经典的逆序对板子,直接做。
然后考虑 增加 后如何更新答案。在所有数的相对关系中,只有最大的数变成了最小的,其他的都没有变化。因此,将最大的数删除掉,并作为最小的数重新插入回去即可。
线段树可以维护这个过程。使用 vector
套 vector
以数字大小为键记录其位置。使用线段树求逆序对的过程中,我们每插入一个数时会计数其后面有多少个比他小的数。删除过程类似,先将所有待删除数的标记取消,然后对与每个数,数一下它后面有多少个比它小的数,从答案中减掉就可以。
增加则是反过来,先数出每个数前有多少个比它大的,然后再把标记恢复。
#include <mrpython/typical_segment_tree.hpp> // https://github.com/Mr-Python-in-China/mp-oi-library
#include <cstddef>
#include <iostream>
using namespace std;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using li = long long int;
int main(void) {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
size_t n, m;
fin >> n >> m;
vector<vector<size_t>> d(m);
for (size_t i = 0; i < n; ++i) {
ui x;
fin >> x;
d[x].emplace_back(i);
}
uli v = 0;
mrpython::typical_segment_tree_add<ui> tree(n, 0);
auto get = [&](size_t l, size_t r) { return l == r ? 0 : tree.get(l, r); };
for (size_t i = m - 1; i < m; --i) {
for (size_t j : d[i]) v += get(0, j);
for (size_t j : d[i]) tree.set(j, mrpython::const_function(1));
}
fout << v << '\n';
for (size_t i = m - 1; i > 0; --i) {
for (size_t j : d[i]) tree.set(j, mrpython::const_function(0));
for (size_t j : d[i]) v -= get(j + 1, n);
for (size_t j : d[i]) v += get(0, j);
for (size_t j : d[i]) tree.set(j, mrpython::const_function(1));
fout << v << '\n';
}
return 0;
}