各点i∈Sについて、iが何回数えられるかを求めればよいので、包除を考えるのがよさそう。点iの上下左右の領域にある点の集合L,R,D,U∈Sを定める:
L(i):={(x,y)∈S∣x<xi}R(i):={(x,y)∈S∣xi<x}D(i):={(x,y)∈S∣y<yi}U(i):={(x,y)∈S∣yi<y}
点iを含むSの部分集合の総数は
2N−2∣L(i)∣−2∣R(i)∣−2∣D(i)∣−2∣U(i)∣+2∣L(i)∩U(i)∣+2∣L(i)∩D(i)∣+2∣R(i)∩U(i)∣+2∣R(i)∩D(i)∣−1
で求まるので、これをi∈Sについて足し合わせればよい。
さて、∣L(i)∣,∣R(i)∣,∣D(i)∣,∣U(i)∣は点をx座標やy座標についてソートしておけば尺取り法や二分探索等でそれぞれ求まる……が、よく見るとxi=xj,yi=yj(i=j)という条件があるので、単に整数0,1,...,N−1が1回ずつ現れるだけであった。したがって、
i∈S∑(2N−1−2∣L(i)∣−2∣R(i)∣−2∣D(i)∣−2∣U(i)∣)=N⋅(2N−1)−4⋅(20+21+...+2N−1)=(N−4)(2N−1)
である。
次に∣L(i)∩D(i)∣,∣L(i)∩U(i)∣,∣R(i)∩D(i)∣,∣R(i)∩U(i)∣を求める。(xi,yi)i∈{1,...,N}をx座標についてソート済み(x1≤x2≤...≤xN)とする。順序付きの集合Oを用意して、y1,y2,...,yNの順にOに入れていく時、点iを処理した時点でOの中のyi未満の点の総数は∣L(i)∩D(i)∣に等しく、yiより大きい点の総数は∣L(i)∩U(i)∣に等しい。同様のことを逆順yN,yN−1,...,y1でやれば∣R(i)∩D(i)∣,∣R(i)∩U(i)∣が求まる。
2Dのクエリを処理できるデータ構造があればテクニックが無くてもできそう。2Dセグメント木とかウェーブレット行列とかいろいろあるようだが、このスライドを眺めていて、とりあえずrange treeがすぐに書けそうに見えたので書いた。かなり重いが一応通った。
fractional cascadingでオーダーを落とすやつも書いた。