Chokudai Speed Run J-転倒数

転倒数、競プロに慣れてないと難しいと思いませんか?僕は難しいと思います。

 

リンク

https://atcoder.jp/contests/chokudai_S001/tasks/chokudai_S001_j

 

f:id:ayaya09:20200102182445p:plain

 

問題は次のようにいいかえられる。

問題概要

自然数Nと、1~Nを並び替えた配列a[1]~a[N]が与えられる。
0 \lt i \lt j \leqq Nかつa[ i ]  \gt a[ j ]を満たすような(i,j)の組の数を求めよ。

 

方針・実装

jについて、(i,j)が条件を満たすようなiの数を数える。a[ i ]  \gt a[ j ]であるから、jを大きいほうからみてうまく数えられないかなーとなる。

 

*注意:説明では1-indexedにしていますが実際は0-indexedのほうがやりやすいと思います。

すでに見た数字がある要素の位置の集合をSとするとき、次のようなことができればよい。(kjの位置)

A.Sのうちkより小さいものの数を求める。

B.Skを挿入する。

 

そのために、セグ木を用いる。このデータ構造は、次のようなことが十分高速にできる。(正確にはO(logN))

・ある要素に値を足す

・ある区間の和を求める

 

これを用いて

[1,k]の要素の和を求める

k番目の要素に1を足す

と、それぞれA,Bに対応する。

 

eq.N=4,a[1]=2,a[2]=4,a[3]=3,a[4]=1の時の転倒数を求める。まず、大きい値から見た位置は[2,3,1,4]である。

 j=2になるような(i,j)の組は、もちろん0である(a[j]はj=2で最大値をとるので)。

ここでセグ木の2の位置に1を加算する。セグ木の中身は、(0,1,0,0)となっている。「次にjが位置kに入るときにあり得るようなiの数」は、セグ木の[1,k]区間の和で求められるこの場合、1の位置に3が入れば答えは0増えるし、4の位置に入れば答えは1増える。この場合33に入るので、j=3のときのiの個数は1であり、セグ木の3 の位置に1を足す。

セグ木の中身は(0,1,1,0)となる。同様に、21の位置に入るのでj=2のときのiの個数は0であり、セグ木の1の位置に1を足す。この時のセグ木の中身は(1,1,1,0)となる。最後に14の位置に入るのでj=1のときのiの個数は3であり,セグ木の中身は(1,1,1,1)となる。求める答えは0+1+0+3=4となる。

 

コード

https://atcoder.jp/contests/chokudai_S001/submissions/9285044