2018 牛客多校第一场 J(线段树)

题目

题意:给你n个数字,给你查询l,r,让你得出1-l 加上r-n里不同的数有几个。

思路:直接把1-n的数字再重新连接到1-n后面,这样你只要求解[r,l+n]的区间不同个数,但是如果l比r大的话,就是求整个区间。预处理完后,再用线段树操作。

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<map>
using namespace std;
const int N=2e5+10;
int n,m;
int cnt[N<<2];
struct qu
{
    int l,r,i;
}q[N];
bool cmp(qu a,qu b)
{
    if(a.r!=b.r)return a.r<b.r;
    else return a.l<b.l;
}
void update(int x,int k,int num,int l,int r)
{
    if(l==r&&l)
    {
        cnt[x]=num;
        return;
    }
    int mid=(l+r)/2;
    if(k<=mid)update(x*2,k,num,l,mid);
    else update(x*2+1,k,num,mid+1,r);
    cnt[x]=cnt[x*2]+cnt[x*2+1];
}
int query(int x,int l,int r,int L,int R)
{
    if(l<=L&&r>=R)
    {
        return cnt[x];
    }
    int mid=(L+R)/2;
    int s=0;
    if(l<=mid)s+=query(x*2,l,r,L,mid);
    if(r>mid)s+=query(x*2+1,l,r,mid+1,R);
    return s;
}
int a[N],b[N];
int ans[N];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        memset(cnt,0,sizeof(cnt));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        for(int i=n+1;i<=2*n;i++)
        {
            b[i]=a[i-n];
        }
        int z=2*n;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            if(q[i].l>q[i].r)
            {
                q[i].l=1;
                q[i].r=n;
                q[i].i=i;
                continue;
            }
            int k=q[i].l+n;
            q[i].l=q[i].r;
            q[i].r=k;
            q[i].i=i;
        }
        sort(q+1,q+m+1,cmp);
        map<int,int>mp;
        mp.clear();
        for(int i=1,j=1;i<=2*n;i++)
        {
            if(mp[b[i]])
            {
                update(1,mp[b[i]],0,1,z);
                update(1,i,1,1,z);
                mp[b[i]]=i;
 
            }
            else
            {
 
                update(1,i,1,1,z);
                mp[b[i]]=i;
            }
            while(j<=m&&q[j].r==i)
            {
                ans[q[j].i]=query(1,q[j].l,q[j].r,1,z);
                j++;
            }
        }
       for(int i=1;i<=m;i++)
        {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/imzxww/article/details/81157290