BOJ 11989 단층
sorohue가 PS하는 블로그
BOJ 11989 단층
문제 링크입니다.
풀이
- 그림을 45도 기울여 생각합시다. 두 쿼리를 x/y방향으로 2배로 미는 것으로 처리해서, 나중에 밀린 양을 반으로 줄이면 됩니다.
- 단층이 밀리는 정도는 방향 별로 계단 모양을 그립니다. 1번 쿼리로는 왼쪽으로 갈수록 밀리는 정도가 커지고, 2번 쿼리로는 오른쪽으로 갈수록 커짐을 알 수 있습니다.
- 단층의 밀림을 역순으로 처리합니다. 그러면, 쿼리를 처리하기 전에 쿼리가 실제로 영향을 미치는 곳을 이후에 반대방향으로 밀릴 거리를 토대로 추론할 수 있습니다.
- 2, 3번을 바탕으로 이분 탐색으로 쿼리가 영향을 미칠 구간의 경계를 찾아낼 수 있습니다. 각 방향으로 밀린 정도를 펜윅 트리로 관리하면서, 이번에 밀려지면서 생겨날 층의 두께와 이후에 반대방향으로 밀어올릴 거리를 비교합니다. Binary Lifting으로 ${\cal O} (\lg N)$에 처리할 수 있습니다.
총 시간 복잡도는 ${\cal O}((N+Q) \lg N)$입니다.
코드
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
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
const int N = 202000;
const int LG = 17;
int n, q;
struct fen{
ll tree[202020]={};
void upd(int i, ll v){for(;i<=N;i+=i&-i)tree[i]+=v;}
ll qry(int i){ll ret=0; for(;i;i-=i&-i)ret+=tree[i]; return ret;}
}xfen, yfen;
void q1(ll x, ll v){ //xfen
int idx = 0; ll sum = 0;
for(int i = LG; i >= 0; i--){
if(idx+(1<<i) <= n && sum+yfen.tree[idx+(1<<i)] <= x-(idx+(1<<i))){
idx += 1<<i;
sum += yfen.tree[idx];
}
}
if(sum <= x-idx){
xfen.upd(1, v);
xfen.upd(idx+1, -v);
}
}
void q2(ll x, ll v){ //yfen
int idx = 0; ll sum = 0;
for(int i = LG; i >= 0; i--){
if(idx+(1<<i) <= n && sum+xfen.tree[idx+(1<<i)] >= (idx+(1<<i))-x){
idx += 1<<i;
sum += xfen.tree[idx];
}
}
idx++;
if(xfen.qry(idx) < idx-x){
yfen.upd(idx, v);
}
}
int main(){
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
cin >> n >> q; vector<ll> x(q+1), d(q+1), v(q+1);
for(int i = 1; i <= q; i++) cin >> x[i] >> d[i] >> v[i];
for(int i = q; i; i--){
if(d[i] == 1) q1(x[i], 2*v[i]);
else q2(x[i], 2*v[i]);
}
for(int i = 1; i <= n; i++) cout << (xfen.qry(i)+yfen.qry(i))/2 << '\n';
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.