017 - Crossing Segments(★7) Editorial by ngtkana


ウェーブレット行列を用いた解法をご紹介します。

入力が \(R _ i\) に関してソート済みであるとして良いです。さらに数列 \(L = (L _ i) _ { i = 1 } ^ N\) に対応するウェーブレット行列 \(W\) を構築しておきます。 線分同士が相異なりかつ交差する条件は \(L _ i \lt L _ j \lt R _ i \lt R _ j\) です。\(j\) を固定すると

  1. \(L _ i \lt L _ j\)
  2. \(\mathop { \mathtt { upper\_bound }} ( R, L _ j ) \le i \lt \mathop { \mathtt { lower\_bound }} ( R, R _ j ) \)

と言い換えられますから、ウェーブレット行列 \(W\)\(\mathop { \mathtt { range\_freq } }\) を用いて、\(L\) の要素であって添字が\(\lbrack \mathop { \mathtt { upper\_bound }} ( R, L _ j ), \mathop { \mathtt { lower\_bound }} ( R, R _ j ) \lbrack\)、値が \(\rbrack -\infty, L _ j \lbrack\) に含まれているものの個数を計算すればよいです。

use itertools::Itertools;
use proconio::{fastout, input, marker::Usize1};
use superslice::Ext;
use wavelet_matrix::WaveletMatrix;

#[fastout]
fn main() {
    input! {
        _total: usize,
        n: usize,
        start_end: [(Usize1, Usize1); n],
    }
    let ends = start_end.iter().map(|&(_, end)| end).sorted().collect_vec();
    let wm = start_end
        .iter()
        .sorted_by_key(|&(_, end)| end)
        .map(|&(start, _)| start)
        .collect::<WaveletMatrix>();
    let ans = start_end
        .iter()
        .map(|&(start, end)| {
            let l = ends.upper_bound(&start);
            let r = ends.lower_bound(&end);
            wm.range_freq(l..r, ..start)
        })
        .sum::<usize>();
    println!("{}", ans);
}

mod wavelet_matrix {
    /* 省略 */
}

提出 (549 ms): https://atcoder.jp/contests/typical90/submissions/28306990

posted:
last update: