牛客网多校赛第一场J题Different Integer

本文介绍了一种使用莫队算法解决特定数列问题的方法。通过给定整数序列和查询对,算法能高效地计算出各查询区间内的不同整数数量。文章提供了完整的代码实现,并详细解释了输入输出格式及限制条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://www.nowcoder.com/acm/contest/139/J
来源:牛客网

Given a sequence of integers a1, a2, …, an and q pairs of integers (l1, r1), (l2, r2), …, (lq, rq), find count(l1, r1), count(l2, r2), …, count(lq, rq) where count(i, j) is the number of different integers among a1, a2, …, ai, aj, aj + 1, …, an.
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test cases contains two integers n and q.
The second line contains n integers a1, a2, …, an.
The i-th of the following q lines contains two integers li and ri.
输出描述:
For each test case, print q integers which denote the result.
示例1
输入
复制
3 2
1 2 1
1 2
1 3
4 1
1 2 3 4
1 3
输出
复制
2
1
3
备注:
* 1 ≤ n, q ≤ 105
* 1 ≤ ai ≤ n
* 1 ≤ li, ri ≤ n
* The number of test cases does not exceed 10.

算法:莫队算法

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9+7;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
#define met(a, b) memset(a, b, sizeof(a))
struct MATION {
    int l, r, id;
} q[2 * maxn];
ll cnt = 0;
int pos[maxn], block, val[maxn], ANS[maxn], a[maxn];
bool vis[maxn];
int d, n, m, top = 0;
int cmp(MATION a, MATION b) {
    if(pos[a.l] != pos[b.l]) return pos[a.l] < pos[b.l];
    else return a.r < b.r;
}
void solve() {
    met(val, 0);
    int ans = 0;
    int l = q[0].l, r = q[0].l - 1;
    for(int i = 0; i < top; i++) {
        while(l < q[i].l) {
            val[a[l]]--;
            if(val[a[l]] == 0) ans--;
            l++;
        }
        while(l > q[i].l) {
            l--;
            val[a[l]]++;
            if(val[a[l]] == 1) ans++;
        }
        while(r < q[i].r) {
            r++;
            val[a[r]]++;
            if(val[a[r]] == 1) ans++;
        }
        while(r > q[i].r) {
            val[a[r]]--;
            if(val[a[r]] == 0) ans--;
            r--;
        }
        ANS[q[i].id] = ans;
    }
}
int main() {
    while(~scanf("%d%d", &n, &m)) {
        met(vis, false);
        cnt = 0;
        block = sqrt(n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            pos[i] = (i - 1) / block + 1;
            pos[i + n] = (i + n - 1) / block + 1;
            a[i + n] = a[i];
            if(!vis[a[i]]) {
                vis[a[i]] = true;
                cnt++;
            }
        }
        int l, r;
        top = 0;
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &l, &r);
            if(r <= l) {
                ANS[i] = cnt;
                continue;
            }
            q[top].l = r;
            q[top].r = n + l;
            q[top].id = i;
            top++;
        }
        sort(q, q + top, cmp);

        solve();
        for(int i = 0; i < m; i++) {
            //cout << ANS[i * 2] << " * " << ANS[i * 2 + 1] << endl;
            printf("%d\n",ANS[i]);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值