競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 190F

ABC190F

転倒数,クエリ問題. 毎回愚直に求めると間に合わないので,差分を更新する. \(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;
}