J-Different Integers-树状数组-区间不同数查询

  •  
  • https://ac.nowcoder.com/acm/contest/139/J
  • 树状数组学习:https://www.cnblogs.com/acgoto/p/8583952.html
  • 题意:给你一个数组, q次询问, 每次询问都会有1个[l, r] 求 区间[1,l] 和 [r, n] 中 数字的种类是多少。
  • 思路:first数组记录每个值第一次出现的位置,last数组记录每个值最后出现的位置,然后按照q次询问的
  • r由小到大排序,tot记录这个序列的不同数字的个数,从1开始一直遍历到最后一个q[m].r在这个过程中,
  • 会经历许多个点,当这个点位置为R并且他里面的值a[R]最后一次出现的位置也是R那么就得在他第一次出现的位置
  • 标记一下,也就是树状数组里面进行维护,给first[a[R]]++,同时,tot--,因为访问到了一个数的终止位置,这个终止位置
  • 可能在1-q[i].L里面,也可能在q[i].L-q[i].R 里面,不管在哪,碰到终止位置我们tot先减去1,然后树状数组求和1-q[i].L被标记
  • 上的数,(被标记的含义是这个数终止位置已经出现,并且tot已经减去了它,所以我需要标记,来判断他到底是在
  • 1-q[i].L里面,还是在q[i].L-q[i].R 里面,如果在1-q[i].L里面,那么你求和肯定能够求出它来,这一个q[i]询问的结果,
  • 自然就是tot-询问的sum值)。
  • #include<bits/stdc++.h>
    using namespace std;
    const int maxn =2e5+100;
    int a[maxn],ans[maxn],n;
    int last[maxn],cnt[maxn];
    int m,tot,first[maxn],r;
    struct node
    {
        int l,r,id;
        bool operator<(const node&b)const
        {
            return r<b.r;
        }
    } q[maxn];
    void add(int x)
    {
        while(x<=n)
        {
            cnt[x]++;
            x+=x&(-x);
        }
    }
    int query(int x)
    {
        int ret=0;
        while(x)
        {
            ret+=cnt[x];
            x-=x&(-x);
        }
        return ret;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            memset(cnt,0,sizeof(cnt));
            memset(last,0,sizeof(last));
            memset(first,0,sizeof(first));
            tot=0;
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
                if(first[a[i]]==0)
                {
                    first[a[i]]=i;
                    tot++;
                }
                last[a[i]]=i;
            }
            for(int i=1; i<=m; i++)
            {
                scanf("%d%d",&q[i].l,&q[i].r);
                q[i].id=i;
            }
            sort(q+1,q+1+m);
            r=1;
            for(int i=1; i<=m; i++)
            {
                while(r<q[i].r)
                {
                    if(last[a[r]]==r)
                    {
                        add(first[a[r]]);
                        tot--;
                    }
                    r++;
                }
                ans[q[i].id]=tot+query(q[i].l);
            }
            for(int i=1; i<=m; i++)
                printf("%d\n",ans[i]);
        }
        return 0;
    }
    
  •  
  •  
  •  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值