我们不以权值建立主席树,而是区间端点作为值建立线段树,一个个插入a[i],我们发现这个数之前是存在的,就需要在上个版本的主席树上减去原来的位置,并加上现在的位置,这样我们在i版本的主席树,维护1-r中,所有数最后一次出现的位置,然后实现区间查询,即可。
/** 按照数字所在的下标建立权值线段树 **/ #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int maxx = 30005; const int maxn = 1e6+7; struct node{ int l,r; int cnt; }tree[maxx*40]; int cnt; int a[maxx]; int pos[maxn]; int root[maxx]; void inserts(int l,int r,int pre,int &now,int pos,int w){ tree[++cnt]=tree[pre]; now=cnt; tree[now].cnt+=w; if (l==r){ return ; } int mid=(l+r)>>1; if (pos<=mid){ inserts(l,mid,tree[pre].l,tree[now].l,pos,w); }else{ inserts(mid+1,r,tree[pre].r,tree[now].r,pos,w); } } int query(int rt,int l,int r,int ql,int qr){ if(ql<=l && r<=qr){ return tree[rt].cnt; } int mid=(l+r)>>1; if (qr<=mid){ return query(tree[rt].l,l,mid,ql,qr); }else if (ql>mid){ return query(tree[rt].r,mid+1,r,ql,qr); }else{ return query(tree[rt].l,l,mid,ql,qr)+query(tree[rt].r,mid+1,r,ql,qr); } } int main(){ int n; while(~scanf("%d",&n)){ cnt=0; memset(root,0,sizeof(root)); memset(pos,0,sizeof(pos)); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); if (!pos[a[i]]){ inserts(1,n,root[i-1],root[i],i,1); pos[a[i]]=i; } else { inserts(1,n,root[i-1],root[i],pos[a[i]],-1); inserts(1,n,root[i],root[i],i,1); pos[a[i]]=i; } } int q; int l,r; scanf("%d",&q); while(q--){ scanf("%d%d",&l,&r); printf("%d ",query(root[r],1,n,l,r)); } } return 0; }