티스토리 뷰
[CF 1042D] Petya and Array - 1800
문제 설명 :
배열 a[1], a[2].. a[n]이 주어져 있다. 여기서 임의의 [l, r] pair를 골랐을 때 $a[l]+a[l+1]+...a[r] < t$ 을 만족하는 pair가 총 몇 쌍인지 세야한다.
문제 풀이 :
$a[l]+a[l+1]+..a[r] < t$ 식을 [1,n]까지의 누적합을 저장하는 누적합배열 $psum[]$ 배열을 활용하여 $psum[r] - psum[l-1] < t$ 로 변형할 수 있다. 그럼 결국에는 $psum[r] - t < psum[l-1]$을 구하는 문제랑 똑같아진다. 변수가 l, r 총 2개이기 때문에 l 이나 r 을 고정시켜놓고 나머지 다른 값만 log만에 구하면 된다. 나는 r을 고정시켜놓고 이를 만족시키는 l의 개수를 구해볼 것이다. 즉 고정된 r에 대해서 $psum[r] - t$ 보다 큰 값을 가지는 $l (1 <= l <= r)$의 값을 구하면 된다.
특정 구간에서 특정 값 x보다 큰(혹은 작은)값의 개수를 구할 때는 offline query와 좌표압축을 사용하면 된다. 좌표압축으로 미리 값이 어느 위치에 들어갈지 배정한 다음, 1~n 원소를 하나씩 보면서 ans에다가 query값을 더해주고 update해주면 된다.
배울 점 :
이 문제에서 r이 아니라 l을 고정하려면 $psum[l-1] + t > psum[r]$ 로 식을 변형하고 이를 만족하는 r (l <= r <= n)을 구해야한다. 그런데 이렇게 하면 위에서 설명한 offline query로 전처리하고 update하는 방식을 사용할 수 없다. 따라서 이런 문제를 풀 때는 항상 left부터 update할 수 있는 방향으로 전처리를 해야한다.
소스코드 :
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int SIZE = 200009;
int tree[SIZE*8],arr[SIZE];
ll psum[SIZE];
int startIdx=1;
int count(int node,int cl, int cr,int ql,int qr){
if(cl > qr || ql > cr) return 0;
if(qr >= cr && cl >= ql) {
return tree[node];
}
int mid = (cl+cr)/2;
return count(node*2,cl,mid,ql,qr) + count(node*2+1,mid+1,cr,ql,qr);
}
void update(int node){
node = node + startIdx - 1;
tree[node]++;
int par = node / 2;
while(par >= 1){
tree[par] = tree[par*2] + tree[par*2+1];
par /= 2;
}
return;
}
int main(){
int n; scanf("%d",&n);
ll t; scanf("%lld",&t);
vector<ll> v;
v.push_back(0);
for(int i=1 ; i<=n ; i++){
scanf("%d",&arr[i]);
psum[i] = psum[i-1] + arr[i];
v.push_back(psum[i]);
}
for(; startIdx < v.size() ; startIdx *= 2);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
map<ll,int> compress;
for(int i=0 ; i<v.size() ; i++){
compress[v[i]] = i + 1;
}
update(compress[0]);
ll ans = 0;
for(int i=1 ; i<=n ; i++){
ll val = psum[i] - t;
int idx = upper_bound(v.begin(),v.end(),val) - v.begin() + 1;
ans += count(1,1,startIdx,idx,startIdx);
update(compress[psum[i]]);
}
printf("%lld\n",ans);
return 0;
}
'Problem Solving > Segment Tree' 카테고리의 다른 글
[BOJ 11658]구간 합 구하기3 (0) | 2021.11.13 |
---|---|
[BOJ 2243] 사탕 상자, [BOJ 9426] 중앙값 측정 (0) | 2021.10.29 |
[BOJ 1517] 버블 소트 (0) | 2021.10.21 |
[BOJ 7469] K번째 수 (0) | 2021.10.20 |
[BOJ 1725] 히스토그램 (0) | 2021.10.15 |