Official

F - Buildings 2 Editorial by toam


ビル \(l,r\ (l<r)\) の両方から見えるビルの条件を考えます.自明な必要条件として

  1. ビル \(l\) から見ることができること
  2. ビル \(r\) より東にあること

があります.これは十分条件にもなっています.

(証明)ビル \(x\ (x>r)\) がビル \(l\) から見ることができるとき,定義からすべての \(k\ (l<k<x)\) に対して \(H_k < H_x\) が成り立ちます.よって,すべての \(k\ (r<k<x)\) に対して \(H_k < H_x\) が成り立つため,ビル \(x\) はビル \(r\) からみることができます.

あとはこれを求める方法を考えます.ABC372-D(Buildings) の解説で書いたように,ビル \(l\) から見ることができるビルの集合はスタックを用いることで管理することができます.本問題では,クエリを先読みしたうえで,ビル \(l\) から見えるビルの集合を管理しているタイミングで,集合に含まれる要素のうち \(r\) より大きいものを同時に求められるようにすれば良いです.これは fenwick tree を用いたり二分探索を用いることで実現できます.

(fenwick tree)

from atcoder.fenwicktree import FenwickTree

n, q = map(int, input().split())
h = list(map(int, input().split()))
query = [[] for i in range(n)]
for i in range(q):
    l, r = map(lambda x: int(x) - 1, input().split())
    query[l].append((r, i))

ft = FenwickTree(n)
stc = []
ans = [0] * q
for l in range(n - 1, -1, -1):
    for r, i in query[l]:
        ans[i] = ft.sum(r + 1, n)
    while stc and h[stc[-1]] < h[l]:
        ft.add(stc.pop(), -1)
    stc.append(l)
    ft.add(l, 1)
print(*ans, sep="\n")

(二分探索)

import bisect
n, q = map(int, input().split())
h = list(map(int, input().split()))
query = [[] for i in range(n)]
for i in range(q):
    l, r = map(lambda x: int(x) - 1, input().split())
    query[l].append((r, i))
ans = [0] * q
stc = []
for l in range(n - 1, -1, -1):
    for r, i in query[l]:
        ans[i] = bisect.bisect_left(stc, -r)
    while stc and h[-stc[-1]] < h[l]:
        stc.pop()
    stc.append(-l)
print(*ans, sep="\n")

posted:
last update: