백준 17671번 두 안테나
풀이 검색해서 풀었다.
통신 가능한 쌍 $i < j$에 대해 $ans[i] = \max(H[i] - H[j])$라고 하자. 이를 세그먼트 트리로 관리하며 스위핑으로 구할 것이다.
$i$는 $[i + A[i], i + B[i]]$ 범위에서 유효하다. $i$가 유효할 때 세그먼트 트리의 $i$번째 인덱스에 $H[i]$를 저장한다. 이후 $j$가 추가될 때, $j - B[j] \le i \le j - A[j]$ 범위의 $i$에 대해 다음과 같이 갱신한다: \(ans[i]=min(ans[i],H[i]−H[j])\)
이때 세그먼트 트리는 lazy propagation으로 $H[j]$를 갱신하고, 노드에는 $H[i]$를 저장함으로써 $ans[i]$를 효율적으로 구할 수 있다.
노드에 구간의 $ans[i]$의 최댓값을 저장하고, $r = j$인 쿼리를 세그먼트 트리에 $[l, r]$ 구간 쿼리를 날려서서 답을 구하면 된다.
같은 과정을 $H[i]$의 부호를 반대로 하여 한 번 더 수행하면 문제를 완전히 해결할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 202020;
const int INF = 1e9 + 7;
struct Node {
int mx = -INF;
int ans = -INF;
Node() {}
Node(int v) : mx(v) {}
};
Node merge(Node a, Node b)
{
Node ret;
ret.ans = max(a.ans, b.ans);
ret.mx = max(a.mx, b.mx);
return ret;
}
struct SegTree {
int n;
vector<int> lazy;
vector<Node> tree;
void init(int _n)
{
n = _n;
lazy.resize(4*n, INF);
tree.resize(4*n);
}
void push(int s, int e, int idx)
{
if(lazy[idx] != INF) {
tree[idx].ans = max(tree[idx].ans, tree[idx].mx - lazy[idx]);
if(s != e) {
lazy[2*idx] = min(lazy[2*idx], lazy[idx]);
lazy[2*idx+1] = min(lazy[2*idx+1], lazy[idx]);
}
lazy[idx] = INF;
}
}
void update(int x, int v, int s, int e, int idx)
{
push(s, e, idx);
if(e < x || x < s) return;
if(s == e) {
tree[idx].mx = v;
return;
}
int m = (s + e) / 2;
update(x, v, s, m, 2*idx);
update(x, v, m+1, e, 2*idx+1);
tree[idx] = merge(tree[2*idx], tree[2*idx+1]);
}
void update_range(int l, int r, int v, int s, int e, int idx)
{
push(s, e, idx);
if(r < s || e < l) return;
if(l <= s && e <= r) {
lazy[idx] = min(lazy[idx], v);
push(s, e, idx);
return;
}
int m = (s + e) / 2;
update_range(l, r, v, s, m, 2*idx);
update_range(l, r, v, m+1, e, 2*idx+1);
tree[idx] = merge(tree[2*idx], tree[2*idx+1]);
}
Node query(int l, int r, int s, int e, int idx)
{
push(s, e, idx);
if(r < s || e < l) return Node();
if(l <= s && e <= r) return tree[idx];
int m = (s + e) / 2;
return merge(query(l, r, s, m, 2*idx), query(l, r, m+1, e, 2*idx+1));
}
void update(int x, int v) { return update(x, v, 1, n, 1); }
void update_range(int l, int r, int v) { return update_range(l, r, v, 1, n, 1); }
Node query(int l, int r) { return query(l, r, 1, n, 1); }
};
int N, H[MAXN], A[MAXN], B[MAXN], Q, L[MAXN], R[MAXN], ans[MAXN];
int main()
{
cin >> N;
for(int i = 1; i <= N; i++) cin >> H[i] >> A[i] >> B[i];
cin >> Q;
for(int i = 1; i <= Q; i++) cin >> L[i] >> R[i];
vector<int> q(Q);
iota(q.begin(), q.end(), 1);
sort(q.begin(), q.end(), [](int i, int j){return R[i] < R[j];});
vector<tuple<int, int, int>> add;
for(int i = 1; i <= N; i++) {
add.emplace_back(i+A[i], i, 1);
add.emplace_back(i+B[i]+1, i, 0);
}
sort(add.begin(), add.end());
int j = 0;
int k = 0;
SegTree seg1, seg2;
seg1.init(N);
seg2.init(N);
for(int i = 1; i <= N; i++) {
while(j < add.size() && get<0>(add[j]) <= i) {
auto [_, idx, op] = add[j++];
if(op) seg1.update(idx, H[idx]), seg2.update(idx, -H[idx]);
else seg1.update(idx, -INF), seg2.update(idx, -INF);
}
seg1.update_range(i-B[i], i-A[i], H[i]);
seg2.update_range(i-B[i], i-A[i], -H[i]);
while(k < q.size() && R[q[k]] <= i) {
int l = L[q[k]];
int r = R[q[k]];
ans[q[k]] = max({seg1.query(l, r).ans, seg2.query(l, r).ans, -1});
k++;
}
}
for(int i = 1; i <= Q; i++) cout << ans[i] << "\n";
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.