ACM训练日记

来源:互联网 发布:下载无人机航拍软件, 编辑:程序博客网 时间:2024/06/06 17:40

这两天继续看了树状数组和线段树,今天晚上做了一个新的专题的题目,是关于树状数组离线处理的

查询给定区间的不同数的个数,

可以记录每一个位置上的点上一次出现的位置,然后把操作安右区间升序,从头开始,每一次将上一个点到当前点的区间部分加一,查询操作区间的右端点的前缀和就可以了

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define MAX 50005
int e[MAX],hash[1000005],last[1000005],ans[200005];
struct node
{
    int l,r,num;
}b[1000005];
bool cmp(node a,node b)
{
    return a.r<b.r;
}
int lowbit(int k)
{
    return k&(-k);
}
void ADD(int k,int v)
{
    while(k<MAX)
    {
        e[k]+=v;
        k+=lowbit(k);
    }
}
long long SUM(int k)
{
    long long re=0;
    while(k)
    {
        re+=e[k];
        k-=lowbit(k);
    }
    return re;
}
int main()
{
    int N,M;
    while(~scanf("%d",&N))
 {
     for(int i=1;i<=N;i++)
     {
            int A;
            scanf("%d",&A);
            hash[i]=last[A]+1;
            last[A]=i;
     }
     scanf("%d",&M);
     for(int i=1;i<=M;i++)
     {
   scanf("%d%d",&b[i].l,&b[i].r);
   b[i].num=i;
     }
        sort(b+1,b+1+M,cmp);
        int now=1;
        for(int i=1;i<=M;i++)
        {
            while(now<=b[i].r)
            {
                  now++;
                  ADD(hash[now-1],1);
                  ADD(now,-1);
            }
            ans[b[i].num]=SUM(b[i].l);
        }
     for(int i=1;i<=M;i++)
   printf("%d\n",ans[i]);
    }
}

原创粉丝点击