📜  门|门CS 2011 |第 39 题(1)

📅  最后修改于: 2023-12-03 14:58:37.177000             🧑  作者: Mango

题目描述

门|门CS 2011 |第 39 题

有一个长度为 $n$ 的由正整数构成的序列 $a_{1}, a_{2}, …, a_{n}$。定义一个数 $x$ 的值为在这个序列中小于等于 $x$ 的数的个数。现在请你编写一个查询系统,它能回答下面两种类型的询问:

1、询问 $[l,r]$ 中有多少个不同的数。

2、询问 $[l,r]$ 中有多少个数的值在 $[a,b]$ 之间。

解题思路

对于第一种询问,我们可以使用 set 或 unordered_set 保存区间中所有数的值。最后返回 set/unordered_set 的大小即可。

对于第二种询问,可以使用前缀和的方式预处理出 $\text{value}[i]$ 即数值为 $i$ 的数的个数,然后用前缀和的方式求出 $\text{value}[i]$ 在区间 $[l, r]$ 中的和即为存在于 $[l, r]$ 中的值在区间 $[a, b]$ 中的个数。

代码示例
#include <bits/stdc++.h>

using namespace std;

vector<int> a;
int n;
int mn, mx;
vector<int> pos[100005];
vector<int> value(100005, 0);

template<typename T>
vector<size_t> sort_indexes(const vector<T> &v) {
    vector<size_t> idx(v.size());
    iota(idx.begin(), idx.end(), 0);
    stable_sort(idx.begin(), idx.end(),
                [&v](const size_t i, const size_t j) { return v[i] < v[j]; });
    return idx;
}

void init() {  // 预处理信息
    cin >> n >> mn >> mx;
    a.resize(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        pos[a[i]].push_back(i);
        value[a[i]]++;
    }
    for (int i = 1; i <= mx; i++) {
        value[i] += value[i - 1];
    }
}

void query1() {
    unordered_set<int> S;
    int l, r;
    cin >> l >> r;

    for (int i = l; i <= r; i++) {
        S.insert(a[i]);
    }

    cout << S.size() << "\n";
}

void query2() {
    int l, r, ai, bi;
    cin >> l >> r >> ai >> bi;
    cout << (value[bi] - value[ai - 1]) - (lower_bound(pos[bi].begin(), pos[bi].end(), r + 1) -
                                        lower_bound(pos[bi].begin(), pos[bi].end(), l))
         << "\n";
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    init();

    int m;
    cin >> m;

    while (m--) {
        int type;
        cin >> type;

        if (type == 1) {
            query1();
        } else {
            query2();
        }
    }

    return 0;
}
Markdown 标记
### 题目描述

[门|门CS 2011 |第 39 题](https://www.luogu.com.cn/problem/P2030)

有一个长度为 $n$ 的由正整数构成的序列 $a_{1}, a_{2}, …, a_{n}$。定义一个数 $x$ 的值为在这个序列中小于等于 $x$ 的数的个数。现在请你编写一个查询系统,它能回答下面两种类型的询问:

1、询问 $[l,r]$ 中有多少个不同的数。

2、询问 $[l,r]$ 中有多少个数的值在 $[a,b]$ 之间。

### 解题思路

对于第一种询问,我们可以使用 set 或 unordered_set 保存区间中所有数的值。最后返回 set/unordered_set 的大小即可。

对于第二种询问,可以使用前缀和的方式预处理出 $\text{value}[i]$ 即数值为 $i$ 的数的个数,然后用前缀和的方式求出 $\text{value}[i]$ 在区间 $[l, r]$ 中的和即为存在于 $[l, r]$ 中的值在区间 $[a, b]$ 中的个数。

### 代码示例

```cpp
{
    code snippet here
}