Given a sequence of n numbers a1, a2, …, an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, …, aj.
Input
Line 1: n (1 ≤ n ≤ 30000).
Line 2: n numbers a1, a2, …, an (1 ≤ ai ≤ 10^6).
Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n).
Output
For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, …, aj in a single line.
Example
Input
5
1 1 2 1 3
3
1 5
2 4
3 5
Output
3
2
3
大致题意:给你n个数,有m次询问,每次查询一个区间[l,r],问这个区间里有多少不同的数。
思路:离线预处理+树状数组或者用主席树在线操作。
代码如下
/*
树状数组
*/
#include
using namespace std;
int n;
int a[30005];
int nex[30005];//记录与第i位置上相同的数的下一个位置坐标
int last[1000005];//记录值a[i]最后出现的位置,a[i]的范围可达1e6,所以该数组需要开到1e6
int Tree[30005];
int ans[200005];
struct node
{
int l,r;
int id;
}q[200005];
bool cmp(node x,node y)
{
return x.l<y.l;
}
int lowbit(int x)
{
return x&-x;
}
int sum(int x)
{
int ans=0;
while(x>0)
{
ans+=Tree[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int date)
{
while(x<=n)
{
Tree[x]+=date;
x+=lowbit(x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),nex[i]=n+1;
memset(last,-1,sizeof(last));
for(int i=1;i<=n;i++)
{
if(last[a[i]]==-1)//如果该位置上的数字是第一次出现,那么add(i,1)
{
last[a[i]]=i;
add(i,1);
}
else
{
nex[last[a[i]]]=i;
last[a[i]]=i;
}
}
int m;
scanf("%d",&m);
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,cmp);
int cnt=1;
for(int i=1;i<=m;i++)
{
while(q[i].l>cnt)
{
add(cnt,-1);//此时我们需要将cnt位置上的值舍去,所以该位置-1
if(nex[cnt]<=n)//如果下一个会出现相同值的数,那么再在下一个位置上加1
add(nex[cnt],1);
cnt++;
}
ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1);//答案即为sum(r)-sum(l-1)
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
主席树
#include
using namespace std;
const int maxn=30005;
int a[maxn],rt[maxn];//保存多颗线段树的根节点
int tot=0;
struct node
{
int l,r;//分别指向左右子树
int size;//该节点对应区间数的个数
}CT[maxn*30];//chairtree
int build(int l,int r)
{
int root=++tot;
CT[root].size=0;
if(l==r) return root;
int m=(l+r)>>1;
CT[root].l=build(l,m);
CT[root].r=build(m+1,r);
return root;
}
int Update(int l,int r,int root,int x,int val)
{
int tmp=++tot;
CT[tot].size=CT[root].size+val;
int m=(l+r)>>1;
if(l==r) return tmp;
else if(x<=m)
{
CT[tmp].l=Update(l,m,CT[root].l,x,val);
CT[tmp].r=CT[root].r;
}
else
{
CT[tmp].l=CT[root].l;
CT[tmp].r=Update(m+1,r,CT[root].r,x,val);
}
return tmp;
}
int query(int l,int r,int root,int pos)
{
if(l==r) return CT[root].size;
int m=(l+r)>>1;
if(pos<=m)
return CT[CT[root].r].size+query(l,m,CT[root].l,pos);
else
return query(m+1,r,CT[root].r,pos);
}
map<int,int> mp;
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
rt[0]=build(1,n);
for(int i=1;i<=n;i++)
{
if(mp.find(a[i])==mp.end())
{
mp[a[i]]=i;
rt[i]=Update(1,n,rt[i-1],i,1);
}
else
{
int tmp=Update(1,n,rt[i-1],mp[a[i]],-1);
rt[i]=Update(1,n,tmp,i,1);
}
mp[a[i]]=i;
}
scanf("%d",&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(1,n,rt[y],x));
}
return 0;
}