BOJ 14504 : 수열과 쿼리 18

2020. 8. 5. 21:32PS/Range Queries

https://www.acmicpc.net/problem/14504

 

14504번: 수열과 쿼리 18

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. 1 i j k: Ai, Ai+1, ..., Aj로 이루어진 부분 수열 중에서 k보다 큰 원소의 개수를 출력한다. 2 i k: Ai를 k로

www.acmicpc.net

우리는 이를 평방 분할(Sqrt Decomposition)로 풀 수 있다.

 

퀴리를 n^(1/2)만큼으로 분할 한 다음, 버킷에 정렬된 결과를 저장해놓으면 

우리는 이를 lower_bound, upper_bound를 통해 k보다 크거나 같은 A_i의 인덱스를 찾을 수 있다. 

그러므로 각 버킷에서 해는 n^(1/2)-(버킷에서 A_i<=k가 최대인 인덱스)가 된다.

 

#include <bits/stdc++.h>
#define MEM 100005
#define sanic ios_base::sync_with_stdio(0)
#define f first
#define s second
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const ll MOD = 1e9+7;
ll n,m;
ll sq;
ll a[MEM];
vector<ll> b[MEM];
void init(){
    sq=sqrt(n);
    for(int i=0; i<n; i++)
        b[i/sq].push_back(a[i]);
    for(int i=0; i<n/sq+1; i++)
        sort(b[i].begin(), b[i].end());
}
void update(int p, int val){
    auto i=lower_bound(b[p/sq].begin(), b[p/sq].end(), a[p]);
    a[p] = val;
    *i = val;
    sort(b[p/sq].begin(), b[p/sq].end());
}
int query(int l, int r, int k){
    int ret=0;
    while(l%sq && l<=r){
        if(a[l++]>k)
            ret++;
    }
    while((r+1)%sq && l<=r){
        if(a[r--]>k)
            ret++;
    }
    while(l<=r){
        ret += b[l/sq].end()-upper_bound(b[l/sq].begin(), b[l/sq].end(), k);
        l += sq;
    }
    return ret;
}
int main()
{
    sanic; cin.tie(0);
    cin >> n;
    for(int i=0; i<n; i++)
        cin >> a[i];
    init();
    cin >> m;
    int q,w,e,s;
    for(int i=0; i<m; i++){
        cin >> q >> w >> e;
        if(q==1){
            cin >> s;
            cout << query(w-1, e-1, s) << '\n';
        }
        else update(w-1, e);
    }
}

Sqrt Decomposition 처음 짜본다. 근데 1트만에 AC가 나왔다는 게 이상한 것 같다.

'PS > Range Queries' 카테고리의 다른 글

BOJ 13547 : 수열과 쿼리 5  (0) 2020.08.05