题意:
已知n个整数。询问q次。想知道每个区间内不同数的个数。
树状数组分析:
先将所有查询按区间右端点从小到大排序,如果一个数已经出现过就先把以前位置上的删掉然后在新的位置上插入,这样[l,r]中重复的就只计算了一次 。
#include<bits/stdc++.h>
using namespace std;
#define SIZE 100005
#define lowbit(x) x&-x
int n,q;
int cnt = 0;
struct Node{
int l,r,id;
bool operator < (const Node &a)const{
return r<a.r;
}
}p[SIZE];
int a[SIZE],pre[SIZE],tree[SIZE],ans[SIZE];
void up(int pos,int value){
while(pos<=n){
tree[pos]+=value;
pos+=lowbit(pos);
}
return ;
}
int query(int pos){
int res=0;
while(pos>0){
res+=tree[pos];
pos-=lowbit(pos);
}
return res;
}
int main(){
while(~scanf("%d",&n)){
memset(pre,0,sizeof(pre));
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d %d",&p[i].l,&p[i].r);
p[i].id=i;
}
sort(p+1,p+1+q);
for(int i=1,j=1;i<=n&&j<=q;i++){
if(pre[a[i]])up(pre[a[i]],-1);
up(i,1);
pre[a[i]]=i;
while(j<=q&&p[j].r<=i){
ans[p[j].id]=query(p[j].r)-query(p[j].l-1);
//3 printf("%d :%d %d %d\n",i,p[j].l,p[j].r,ans[p[j].id]);
j++;
}
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
}
}
主席树:
#include<bits/stdc++.h>
using namespace std;
#define SIZE 1000005
int a[SIZE];
int root[SIZE];
int pre[SIZE];
struct Node
{
int l,r;
int sum;
} p[SIZE];
int cnt=0;
int bulid(int l,int r)
{
int c = ++cnt;
p[c].sum = p[c].l = p[c].r = 0;
if(l == r)
return c;
int mid = l+r>>1;
p[c].l = bulid(l,mid);
p[c].r = bulid(mid+1,r);
return c;
}
int update(int pos,int now,int val,int l,int r)
{
int c = ++cnt;
p[c] = p[now];
p[c].sum += val;
if(l == r)
return c;
int m = (l+r)>>1;
if (m >= pos)
{
p[c].l = update(pos,p[now].l,val,l,m);
}
else
{
p[c].r = update(pos,p[now].r,val,m+1,r);
}
return c;
}
int query(int pos,int now,int l,int r)
{
if(l == r)
return p[now].sum;
int m = (l+r)>>1;
if(m >= pos)
{
return p[p[now].r].sum+query(pos,p[now].l,l,m);
}
else
return query(pos,p[now].r,m+1,r);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
cnt=0;
memset(pre,0,sizeof(pre));
memset(a,0,sizeof(a));
memset(root,0,sizeof(root));
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
root[0]=bulid(1,n);
for (int i = 1 ; i <= n; ++i)
{
int v = a[i];
if (pre[v] == 0)
{
root[i] = update(i,root[i-1],1,1,n);
}
else
{
int t = update(pre[v],root[i-1],-1,1,n);
root[i] = update(i,t,1,1,n);
}
pre[v] = i;
}
int q,l,r;
scanf("%d",&q);
while(q--)
{
scanf("%d %d",&l,&r);
//printf("%d %d\n",l,root[r]);
printf("%d\n",query(l,root[r],1,n));
}
}
}