문제는 https://www.acmicpc.net/problem/8177 링크에서 풀어볼 수 있다.
문제 설명: 초기에 1~n 크기의 신발들이 각각 k쌍 씩 있다. 그리고 신발의 크기가 r인 사람은 r~r+d 크기의 신발을 신을 수 있다. 이때, m개의 상황이 생기는데, 각각의 상황은 2가지 종류 중 하나이다. (1) 신발 크기가 ri인 사람 xi 명이 온다. (2) 신발 크기가 ri인 사람 xi명이 나간다. (당연하지만 안 들어온 사람은 못 나간다.) 들어오는지 나가는지는 xi의 부호로 구별할 수 있다. 각각의 상황이 발생했을 때, 현재 있는 모든 사람에게 위 조건을 만족하도록 신발을 분배할 수 있는지 여부를 묻는 문제이다. (들어오는 사람에게 신발을 주는 개념이 아니라 상황이 발생할 때마다 최대한 위 조건을 만족시키도록 처음부터 재분배하는 개념이다.)
변수 조건: (1≤n≤200,000, 1≤m≤500,000, 1≤k≤109, 0≤d <n) 단 ri, xi는 (1≤ri≤n-d, −109≤xi≤109)
문제풀이: 문제 조건을 적당히 이리저리 처리해보면 신발 크기가 i인 사람의 수를 저장하는 배열 p[i]에서 k를 뺸 배열에서의 최대 연속합이 d*k를 초과하지 않아야 한다는 것을 알 수 있다. 따라서 이를 세그먼트 트리로 O(log n)만에 배열의 최대연속합을 구하고 이것이 d*k를 초과하는지 여부로 출력을 하면된다.
배열 p[i]-k에서 매 구간의 최대연속합은 다음 3개중 하나이다. i) 왼쪽 절반구간에서의 최대값 ii) 오른쪽 절반구간에서의 최대값 iii) 왼쪽 절반구간의 접미사 합 값의 최대값 + 오른쪽 절반구간의 접두사 합 값의 최대값. 각각 구간에서의 최대값, 총합, 접미사 합 최대값, 접두사 합 최대값을 배열에 저장해 세그먼트 트리 쿼리 처리하듯이 구해주면 된다. 따라서 시간복잡도 O(m*log n).
시행착오와 했던 생각: 처음 문제 보았을때, 뭔가 딱 전형적인 쿼리 문제로 O(nlogm) 느낌이 났다. 또, log 형식 쿼리니 세그먼트 트리 구성하면 될것 같았다. 또, 문제조건 처리하는 것 까지는 문제가 없었는데 하... ri≤n-d 조건을 보지 못하고 저부분을 이상하게 처리해주다가 WA가 많이 나왔다. 또, 중간에 구간 max를 그 구간의 전체합이라고 착각하고 코드를 짜서 틀려버렸다.. 문제를 항상 정확히 읽고, 더 많이 풀어보면서 구현실수랑 짜는데 걸리는 시간을 줄여야겠다.
풀이 코드:
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
|
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pi;
ll n,m,k,d;
ll lf[800006],rg[800006],ar[200005],tree[800006],sum[800006];
ll getupd(ll l,ll r,ll nd,ll c)
{
if(r<c||c<l) return tree[nd];
if(l==r&&l==c)
{
lf[nd]=ar[l],rg[nd]=ar[l],sum[nd]=ar[l];
return tree[nd]=ar[l];
}
ll md=(l+r)>>1,ret=-1e17;
ll candl=getupd(l,md,nd*2,c),candr=getupd(md+1,r,nd*2+1,c);
sum[nd]=sum[nd*2]+sum[nd*2+1];
lf[nd]=max(sum[nd*2]+lf[nd*2+1],lf[nd*2]);
rg[nd]=max(sum[nd*2+1]+rg[nd*2],rg[nd*2+1]);
ret=max(ret,candl),ret=max(ret,candr);
ret=max(ret,rg[nd*2]+lf[nd*2+1]);
return tree[nd]=ret;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>n>>m>>k>>d;
for(int i=1;i<=n;i++)
ar[i]=-k,getupd(1,n,1,i);
for(int i=1;i<=m;i++)
{
ll a,b;cin>>a>>b;
ar[a]+=b;
ll c=getupd(1,n,1,a);
if(c>k*d) cout<<"NIE"<<"\n";
else cout<<"TAK"<<"\n";
}
return 0;
}
|
'PS 풀이 및 정리 > POI' 카테고리의 다른 글
POI Deque 문제(BOJ 8201번 Pilots , 10129번 작은 새) (0) | 2019.09.13 |
---|