結果

問題 No.2873 Kendall's Tau
ユーザー LyricalMaestro
提出日時 2025-03-01 03:32:25
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 4,785 bytes
コンパイル時間 623 ms
コンパイル使用メモリ 82,400 KB
実行使用メモリ 54,388 KB
最終ジャッジ日時 2025-03-01 03:32:35
合計ジャッジ時間 8,606 ms
ジャッジサーバーID
(参考情報)
judge6 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 4 TLE * 1 -- * 25
権限があれば一括ダウンロードができます

ソースコード

diff #

## https://yukicoder.me/problems/no/2873

import math

class SegmentTree:
    """
    非再帰版セグメント木。
    更新は「加法」、取得は「最大値」のもの限定。
    """

    def __init__(self, init_array):
        n = 1
        while n < len(init_array):
            n *= 2
        
        self.size = n
        self.array = [[] for _ in range(2 * self.size)]
        for i, a in enumerate(init_array):
            self.array[self.size + i] = a
        
        end_index = self.size
        start_index = end_index // 2
        while start_index >= 1:
            for i in range(start_index, end_index):
                self._op(self.array[i], self.array[2 * i], self.array[2 * i + 1])
            end_index = start_index
            start_index = end_index // 2
    
    def _op(self, array, left, right):
        array.clear()
        l_index = 0
        r_index = 0
        while l_index < len(left) or r_index < len(right):
            if l_index == len(left):
                array.append(right[r_index])
                r_index += 1
            elif r_index == len(right):
                array.append(left[l_index])
                l_index += 1
            else:
                if left[l_index] <= right[r_index]:
                    array.append(left[l_index])
                    l_index += 1
                else:
                    array.append(right[r_index])
                    r_index += 1
                

    def add(self, x, a):
        index = self.size + x
        self.array[index].append(a)
        while index > 1:
            index //= 2
            self._op(self.array[index], self.array[2 * index], self.array[2 * index + 1])

    def get_positive(self, l, r, y):
        L = self.size + l; R = self.size + r

        # 2. 区間[l, r)の最大値を求める
        s = 0
        while L < R:
            if R & 1:
                R -= 1
                s += self.positive(self.array[R], y)
            if L & 1:
                s += self.positive(self.array[L], y)
                L += 1
            L >>= 1; R >>= 1
        return s

    def get_negative(self, l, r, y):
        L = self.size + l; R = self.size + r

        # 2. 区間[l, r)の最大値を求める
        s = 0
        while L < R:
            if R & 1:
                R -= 1
                s += self.negative(self.array[R], y)
            if L & 1:
                s += self.negative(self.array[L], y)
                L += 1
            L >>= 1; R >>= 1
        return s

    def positive(self, array, y):
        if len(array) == 0:
            return 0

        if array[-1] <= y:
            return 0
        
        low = 0
        high = len(array) - 1
        while high - low > 1:
            mid  = (high + low) // 2
            if array[mid] > y:
                high = mid
            else:
                low = mid
        if array[low] > y:
            return len(array) - low
        else:
            return len(array) - high

    def negative(self, array, y):
        if len(array) == 0:
            return 0

        if array[0] >= y:
            return 0
        
        low = 0
        high = len(array) - 1
        while high - low > 1:
            mid  = (high + low) // 2
            if array[mid] < y:
                low = mid
            else:
                high = mid
        if array[high] < y:
            return high + 1
        else:
            return low + 1

def main():
    N = int(input())
    xy = []
    for _ in range(N):
        x, y = map(int, input().split())
        xy.append((x, y))

    # R, Sの計算
    R = 0
    S = 0
    x_map = {}
    y_map = {}
    tot = 0
    for x, y in xy:
        if x in x_map:
            R += tot - x_map[x]
        else:
            R += tot
        if y in y_map:
            S += tot - y_map[y]
        else:
            S += tot

        if x not in x_map:
            x_map[x] = 0
        x_map[x] += 1
        if y not in y_map:
            y_map[y] = 0
        y_map[y] += 1
        tot += 1
    
    # P,Qの計算

    ## xについての座標圧縮
    x_set = set()
    for x, _ in xy:
        x_set.add(x)
    x_list = list(x_set)
    x_list.sort()
    x_map = {}
    for i, x in enumerate(x_list):
        x_map[x] = i
    x_max = len(x_list)

    seg_tree = SegmentTree([[] for _ in range(x_max + 1)])
    P = 0
    Q = 0
    for x, y in xy:
        x_ = x_map[x]

        p1 = seg_tree.get_negative(0, x_, y)
        p2 = seg_tree.get_positive(x_ + 1, seg_tree.size, y)
        P += p1 + p2

        q1 = seg_tree.get_positive(0, x_, y)
        q2 = seg_tree.get_negative(x_ + 1, seg_tree.size, y)
        Q += q1 + q2

        seg_tree.add(x_, y)
    
    answer = (P - Q) / math.sqrt(R * S)
    print(answer)


if __name__ == "__main__":
    main()
0