牛客网暑期ACM多校训练营(第一场) - J Different Integers(线段数组or莫队)

本文提供了一种解决ACM竞赛中不同整数计数问题的有效方法,利用离线处理和线段树数据结构来快速计算指定区间内的不同整数数量。

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

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

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Given a sequence of integers a 1, a 2, ..., a n and q pairs of integers (l 1, r 1), (l 2, r 2), ..., (l q, r q), find count(l 1, r 1), count(l 2, r 2), ..., count(l q, r q) where count(i, j) is the number of different integers among a 1, a 2, ..., a i, a j, a j + 1, ..., a n.

输入描述:

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 a
1
, a
2
, ..., a
n
.
The i-th of the following q lines contains two integers l
i
 and r
i
.

输出描述:

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 ≤ 10
5

* 1 ≤ a
i
 ≤ n
* 1 ≤ l
i
, r
i
 ≤ n
* The number of test cases does not exceed 10.


骚操作:直接把数组*2 然后求1-L,R-N 就变成 求R-L+N之间的不同数的个数了;注意,主席树会TLE;要用线段数组+离线

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
 
using namespace std;
const int maxn=300000+5;
map<int,int> mp;
int data[maxn];
int a[maxn];
int ans[200000+5];
struct node{
    int l,r,id;
    bool operator<(node t)const{
        return r<t.r;
    }
}q[200000+5];
int sum(int i){
    int ans=0;
    while(i>0){
        ans+=data[i];
        i-=i&-i;
    }
    return ans;
}
void add(int i,int x){
    while(i<maxn){
        data[i]+=x;
        i+=i&-i;
    }
}
 
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        fill(data,data+n*2+2,0);
        mp.clear();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i+n]=a[i];
        }
        n=n*2;
 
 
        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            q[i].l=y;
            q[i].r=x+n/2;
            q[i].id=i;
        }
        sort(q,q+m);
        int pre=1;
        for(int i=0;i<m;i++){
            for(int j=pre;j<=q[i].r;j++){
                if(mp[a[j]]!=0){
                    add(mp[a[j]],-1);
                }
                add(j,1);
                mp[a[j]]=j;
            }
            pre=q[i].r+1;
            ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1);
        }
        for(int i=0;i<m;i++){
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

 

也可以莫队加上读入挂

#include<bits/stdc++.h>
 
using namespace std;
int n,q,a[100005];
int L,R,ans;
struct node{
    int l,r,id;
};
node temp[100005];
int sum[1000005];
int anw[1000005];
int block[100005];
int read()
{
    char ch=' ';
    int ans=0;
    while(ch<'0' || ch>'9')
        ch=getchar();
    while(ch<='9' && ch>='0')
    {
        ans=ans*10+ch-'0';
        ch=getchar();
    }
    return ans;
}
int cmp(node a,node b){
    if(block[a.l]==block[b.l])return block[a.r]<block[b.r];
    return block[a.l]<block[b.l];
}
void add(int x){
    if(sum[x]==0)ans++;sum[x]++;
}
void del(int x){
    sum[x]--;if(sum[x]==0)ans--;
}
int main()
{
 
    ios::sync_with_stdio(false);
    while(~scanf("%d%d",&n,&q)){
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            a[i]=read();
            block[i]=i/sqrt(n);
        }
        for(int i=1;i<=q;i++){
            temp[i].l=read();
            temp[i].r=read();
            temp[i].id=i;
        }
        sort(temp+1,temp+1+q,cmp);
        L=0;R=n+1;ans=0;
        for(int i=1;i<=q;i++){
            while(L<temp[i].l)L++,add(a[L]);
            while(R>temp[i].r)R--,add(a[R]);
            while(L>temp[i].l)del(a[L]),L--;
            while(R<temp[i].r)del(a[R]),R++;
            anw[temp[i].id]=ans;
        }
        for(int i=1;i<=q;i++)printf("%d\n",anw[i]);
 
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/luowentao/p/9338237.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值