这个题加深了我对主席树的理解~题解的过程是扫描数列建立持久化线段树,若是第一次出现,就在该数位置加一;不是的话,上次出现的位置减一,新位置加一。对于每个询问区间[L,R]在第R个版本的线段树上只有前R个数,在线段树上查询位置L,对经过的区间进行累加。

这个做法我想了好久啊==为毛这么建树啊啊啊。举两个极端的栗子:

1所有的数字没有重复的,该数位置加一,和前一个题一样,没得说

2所有数字都是同一个,从第二次出现,上次位置的cnt由1变成0了,新建了一个为1的点,依次循环,那么最后整个树,只有那么一条(从根节点到那个点)整个路径上的结点值是1,其他所有结点值都是0

再说那个处理结果的方法,其实题解说的真的太不明白了==由于每个版本的树都是存储【1,R】范围内的数,如果发现L在1~R中点的左侧,那么不用说,中点右侧的cnt值一定得加到最终结果中;如果发现L在中点右侧,当然是L右侧就足够了,在中点~R区间内找L

/*********
spoj D-query
2016.1.24
27648	340
C++ (g++ 4.3.2)
*********/
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int maxn=100001;
struct Node
{
    int ls,rs,cnt;
}tr[maxn*20];
int cur,rt[maxn];
void init(){cur=0;}
inline void push_up(int o)
{
    tr[o].cnt=tr[tr[o].ls].cnt+tr[tr[o].rs].cnt;
}
int build(int l,int r)
{
    int k=cur++;
    if(l==r)
    {
        tr[k].cnt=0;
        return k;
    }
    int mid=(l+r)>>1;
    tr[k].ls=build(l,mid);
    tr[k].rs=build(mid+1,r);
    push_up(k);
    return k;
}
int update(int o,int l,int r,int pos,int val)
{
    int k=cur++;
    tr[k]=tr[o];
    if(l==pos&&r==pos)
    {
        tr[k].cnt+=val;
        return k;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) tr[k].ls=update(tr[o].ls,l,mid,pos,val);
    else tr[k].rs=update(tr[o].rs,mid+1,r,pos,val);
    push_up(k);
    return k;
}
int query(int l,int r,int o,int pos)
{
    if(l==r) return tr[o].cnt;
    int mid=(l+r)>>1;
    if(pos<=mid) return tr[tr[o].rs].cnt+query(l,mid,tr[o].ls,pos);
    else return query(mid+1,r,tr[o].rs,pos);
}
int b[maxn];
map<int,int>mp;
int main()
{
    int n,m;
    while(~scanf("%d",&n))
    {
        mp.clear();
        init();
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        rt[0]=build(1,n);
        for(int i=1;i<=n;i++)
        {
            if(mp.find(b[i])==mp.end())
            {
                mp[b[i]]=i;
                rt[i]=update(rt[i-1],1,n,i,1);
            }
            else
            {
                int tmp=update(rt[i-1],1,n,mp[b[i]],-1);
                rt[i]=update(tmp,1,n,i,1);
            }
            mp[b[i]]=i;
        }
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            int ans=query(1,n,rt[b],a);
            printf("%d\n",ans);
        }
    }
    return 0;
}