传送门:SPOJ - DQUERY
题目大意
给定一个序列,求然后有q次查询求[L,R]区间中不同数字的个数
解题思路
主席树模版类型题目,离散化,更新查询
AC代码
#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
const int MX = 1e5+5;
const int N = MX*20;
int n,q,tot;
int A[MX];
int T[N],lson[N],rson[N],sum[N];
int build(int l,int r)
{
int rt = tot++;
sum[rt] = 0;
int mid = (l+r)>>1;
if(l!=r) {
lson[rt] = build(l,mid);
rson[rt] = build(mid+1,r);
}
return rt;
}
int update(int rt,int pos,int val)
{
int nrt = tot++;
int tmp = nrt;
int l=1,r=n;
sum[nrt] = sum[rt] + val;
while(l<r) {
int mid = (l+r)>>1;
if(pos<=mid) {
lson[nrt] = tot++;
rson[nrt] = rson[rt];
nrt = lson[nrt];
rt = lson[rt];
r = mid;
} else {
rson[nrt] = tot++;
lson[nrt] = lson[rt];
nrt = rson[nrt];
rt = rson[rt];
l = mid+1;
}
sum[nrt] = sum[rt]+val;
}
return tmp;
}
int query(int rt,int pos)
{
int l= 1,r = n,ret = 0;
while(pos>l) {
int mid = (l+r)>>1;
if(pos>mid) {
l = mid+1;
rt= rson[rt];
} else{
r = mid;
ret += sum[rson[rt]];
rt = lson[rt];
}
}
return ret+sum[rt];
}
int main()
{freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
T[0] = build(1,n);
map<int,int>mp;
for(int i=1;i<=n;i++) {
if(mp.find(A[i])==mp.end()) T[i] = update(T[i-1],i,1);
else {
int tmp = update(T[i-1],mp[A[i]],-1);
T[i] = update(tmp,i,1);
}
mp[A[i]] = i;
}
scanf("%d",&q);
while(q--) {
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(T[r],l));
}
return 0;
}