题目链接:https://www.luogu.org/problemnew/show/P1972
题目大意:


对于一个查询[L, R],如果一个数组重复在数组中出现[1, R],我们只关心它最后一次出现的位置。

查询[2, 4]和[1, 5],我们按R排序。

p为首指针, 我们建立一棵权值数状数组。


现在可以得到[2, 4]的不同元素个数,query(4)-query(1)=3


现在可以得到[1, 5]的不同元素个数:query(5)-query(0)=3

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//由块号寻找第一个块元素的下标
#define LL(x) ((x-1)*Len+1)

struct node
{
    int L, R, k;
}q[500050];

int sum[1000010]={0};
int a[500050], n=1000010;//数组的最大值,太大时离散化
int vis[1000010]={0};
int ans[500050]={0};

int cmp(node a, node b)
{
    return a.R<b.R;
}

void add(int p, int y)
{
    while(p<=n)
    {
        sum[p]+=y;
        p+=(p&-p);
    }
}

int cx(int p)
{
    int ans=0;
    while(p)
    {
        ans+=sum[p];
        p-=(p&-p);
    }
    return ans;
}

int main()
{
    int n, m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].L,&q[i].R);
        q[i].k=i;
    }
    sort(q+1, q+1+m, cmp);//按查询的R排序
    
    int it=1;
    for(int i=1;i<=m;i++)
    {
        for(; it<=q[i].R;it++)
        {
            if(vis[a[it]])//这个数之前出现过
            {
                add(vis[a[it]], -1);//取消标记
            }
            vis[a[it]]=it;//记录最大位置
            
            add(it, 1);//添加新标记
        }

        it=q[i].R+1;
        ans[q[i].k]=cx(q[i].R)-cx(q[i].L-1);//查询
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",ans[i]);
    }

    return 0;
}