転倒数,クエリ問題. 毎回愚直に求めると間に合わないので,差分を更新する. \(b\) の先頭を一番後ろに持ってきても, 転倒数を計算するときの処理の大部分は使いまわせる. 先頭からの削除と,後ろへの追加を別々に処理出来れば十分.
\(b\) の先頭を一番後ろに持って行ったときの, 転倒数の変化を調べる. 例えば \(b = [2,0,3,1]\) のとき, \(b_{0} = 2\) が転倒数に与えている変化を調べる. 先頭から削除したことで,転倒数が \(b_{0} = 2\) だけ減る. 後ろに追加したことで,転倒数が \(N-1-b_{0}\) だけ増える.
使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"
ll op(ll a, ll b) {return a+b;}
ll e() {return 0LL;}
int main() {
ll n;
cin >> n;
vll a(n); rep(i,n) { cin >> a[i]; }
segtree<ll,op,e> tr(n);
ll ans = 0;
drep(i,n){
ans += tr.prod(0, a[i]);
tr.set(a[i], tr.get(a[i])+1);
}
ll t = ans;
rep(i,n){
cout << ans << endl;
ans -= a[i];
ans += n-1-a[i];
}
assert(t == ans);
return 0;
}