牛客网暑期ACM多校训练营(第一场) J Different Integers【离线+树状数组||莫队||主席树】

https://www.nowcoder.com/acm/contest/139/J

树状数组:询问两端区间其中不同数字的个数,可以离线,可以复制区间使得两个区间变成一个区间上的询问。

莫队:同样是离线,对于这个题来说有些许暴力,不过问题不大。

树状数组:

#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+45;
#define INF 0x3f3f3f3f;
#define ll long long int
#define charmax(x,y) x=max(x,y)
#define charmin(x,y) x=min(x,y)
#define clr(x,p) memset(x,p,sizeof x)
int n,m;
struct node{
int u,v;int id,ans;}q[maxn];
int a[2*maxn];
int c[2*maxn];
int num[2*maxn];
int pos[2*maxn];
void add(int x,int p){for(int i=x;i<=n;i+=i&-i)c[i]+=p;}
int query(int x) {int ans=0;for(int i=x;i>0;i-=i&-i)ans+=c[i];return ans;}
int cmp(node a,node b){
return a.v<b.v;}
int cmp2(node a,node b){
return a.id<b.id;}
int main()
{
    while(~scanf("%d %d",&n,&m)){
    clr(c,0);clr(num,0);clr(pos,-1);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=n+1;i<=2*n;i++){
        a[i]=a[i-n];
    }
    for(int i=1;i<=m;i++){
        scanf("%d %d",&q[i].u,&q[i].v);
        q[i].u+=n;
        swap(q[i].u,q[i].v);
        q[i].id=i;
    }
    n=n*2;
    for(int i=1;i<=n;i++){
        if(!num[a[i]]){
            num[a[i]]=i;
        }
        else{
            pos[i]=num[a[i]];
            num[a[i]]=i;
        }
    }
    sort(q+1,q+1+m,cmp);int cs=1;
    for(int i=1;i<=n&&cs<=m;i++){
        add(i,1);
        if(pos[i]!=-1){
            add(pos[i],-1);
        }
        while(i==q[cs].v&&cs<=m){
            q[cs].ans=query(q[cs].v)-query(q[cs].u-1);
            cs++;
        }
    }
    //cout<<c[2]<<endl;
    sort(q+1,q+1+m,cmp2);
    for(int i=1;i<=m;i++){
        printf("%d\n",q[i].ans);
    }

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值