牛客网暑期ACM多校训练营(第一场)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 a 1, 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 l i and ri.

输出描述:

For each test case, print q integers which denote the result.

备注

* 1 ≤ n, q ≤ 10^5

* 1 ≤ ai ≤ n

* 1 ≤ li, ri ≤ n

* The number of test cases does not exceed 10.

示例1:

输入

3 2

1 2 1

1 2

1 3

4 1

1 2 3 4

1 3

输出

2

1

3

就是做过的一道题

作者:scaufa
链接:https://www.nowcoder.com/discuss/87249?type=101&order=0&pos=6&page=0
来源:牛客网

首先将原数组扩展为2倍长的,即 a[i+n] = a[i]

对于查询a[1...l]和a[r..n]有多少种不同的数字可以转换为查询 a[r...l+n]有多少种不同的数字

首先考虑维护一个前缀和,pre[i]表示a[1...i]有多少种不同的数字,那么对于a[l...r]的答案就为pre[r] - pre[l-1] + 在a[l...r]和a[1...l-1]同时出现的数字的种类

对于如何求在a[l...r]和a[1...l-1]同时出现的数字的种类,可以考虑使用树状数组维护,树状数组的第i个点表示a[i]是否已经在1...l出现过,对于每个查询只需要查树状数组中l~r的区间和即可

那么我们只要对区间查询进行排序,对于左端每次右移的时候把对应的数的下一个位置加入到数状数组中即可。

const int maxn=400010;
int lb(int x){return x&-x;}
int n,m,k,q;
int a[maxn],sum[maxn],nex[maxn];
int c[maxn],ans[maxn];
int ct,cnt,tmp,flag;
int vis[maxn];
void add(int x,int v)
{
    while(x<maxn)
    {
        a[x]+=v;
        x+=lb(x);
    }
}
int query(int x)
{
    int an=0;
    while(x>0)
    {
        an+=a[x];
        x-=lb(x);
    }
    return an;
}
struct node
{
    int l;int r;
    int id;
    bool operator<(node aa)const
    {
        return r<aa.r;
    }
}qq[maxn];
int main()
{
    while(scanf("%d %d",&n,&q)!=EOF)
    {
        flag=1;
        memset(a,0,sizeof(a));
        memset(vis,0,sizeof(vis));
        memset(nex,0,sizeof(nex));
        for(int i=1;i<=n;i++){
            scanf("%d",&c[i]);
            c[i+n]=c[i];
        }
        for(int i=0;i<q;i++)
        {scanf("%d%d",&qq[i].l,&qq[i].r);qq[i].id=i;}
        sort(qq,qq+q);
        int j=qq[0].r,k=1;
        for(int i=1;i<=n*2;i++)
        {
            if(!vis[c[i]])
            {
                vis[c[i]]=i;
                add(i,1);
            }
            else
            {
                nex[vis[c[i]]]=i;
                vis[c[i]]=i;
            }
        }
        for(int i=0;i<q;i++)
        {
            while(k<qq[i].r)
            {
                int t=query(k);
                if(t) {
                add(k,-1);
                if(nex[k]) add(nex[k],1);
                }
                k++;
            }
            //k=qq[i].r;
            ans[qq[i].id]=query(n+qq[i].l);
        }
        for(int i=0;i<q;i++) printf("%d\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/snayf/article/details/81138871