NOIP之前写过这题,先用的分块。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=50005; 4 int t[N+10],a[N+10]; 5 int v[1000005]; 6 int sum=0; 7 void add(int x) 8 { 9 v[x]++; 10 if(v[x]==1)sum++; 11 } 12 void del(int x) 13 { 14 v[x]--; 15 if(v[x]==0)sum--; 16 } 17 int sq; 18 struct node 19 { 20 int l,r,id; 21 bool operator <(const node &b)const 22 { 23 if((l/sq)==(b.l/sq))return r<b.r; 24 return l<b.l; 25 } 26 }p[200005]; 27 int ans[200005]; 28 int main() 29 { 30 int n;scanf("%d",&n); 31 sq=sqrt((double)n); 32 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 33 int m; 34 scanf("%d",&m); 35 for(int i=1;i<=m;++i) 36 { 37 scanf("%d%d",&p[i].l,&p[i].r); 38 p[i].id=i; 39 } 40 sort(p+1,p+1+m); 41 int l=0,r=0; 42 for(int i=1;i<=m;++i) 43 { 44 while(r>p[i].r)del(a[r--]); 45 while(r<p[i].r)add(a[++r]); 46 while(l<p[i].l)del(a[l++]); 47 while(l>p[i].l)add(a[--l]); 48 ans[p[i].id]=sum; 49 } 50 for(int i=1;i<=m;++i)printf("%d\n",ans[i]); 51 return 0; 52 }
又采用了树状数组,离线按右端点排序,只关心最后一个出现的位置,如果有更新的则将原来的-1将新的位置+1
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=50005; 4 int t[N+10],a[N+10],b[N+10]; 5 int v[N+10]; 6 int lowbit(int x){ 7 return x&(-x); 8 } 9 void add(int x,int y) 10 { 11 for(;x<=N;x+=lowbit(x))t[x]+=y; 12 } 13 int query(int x) 14 { 15 int ans=0;for(;x;x-=lowbit(x))ans+=t[x];return ans; 16 } 17 struct node 18 { 19 int l,r,id; 20 bool operator <(const node &b)const 21 { 22 if(r==b.r)return l<b.l; 23 return r<b.r; 24 } 25 }p[200005]; 26 int ans[200005]; 27 int main() 28 { 29 int n; 30 scanf("%d",&n); 31 for(int i=1;i<=n;++i){scanf("%d",&a[i]);b[i]=a[i];} 32 sort(b+1,b+1+n); 33 for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+1+n,a[i])-b; 34 int m; 35 scanf("%d",&m); 36 for(int i=1;i<=m;++i) 37 { 38 scanf("%d%d",&p[i].l,&p[i].r); 39 p[i].id=i; 40 } 41 sort(p+1,p+1+m); 42 int pos=1; 43 for(int i=1;i<=m;++i) 44 { 45 while(pos<=p[i].r) 46 { 47 if(v[a[pos]])add(v[a[pos]],-1); 48 v[a[pos]]=pos;add(v[a[pos]],1);pos++; 49 } 50 ans[p[i].id]=query(p[i].r)-query(p[i].l-1); 51 } 52 for(int i=1;i<=m;++i)printf("%d\n",ans[i]); 53 return 0; 54 }
现在我又学了主席树,我们只要对于last(上一次的位置)建主席树,然后查询0~l-1这个区间出现的个数即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6+10; 4 struct node 5 { 6 int l,r,s; 7 }t[N<<2]; 8 int n,m,cnt,last[N],pos[N],rt[N]; 9 void change(int &x,int l,int r,int pos) 10 { 11 t[++cnt]=t[x];x=cnt; 12 if(l==r){t[x].s++;return;} 13 int mid=l+r>>1; 14 if(pos<=mid)change(t[x].l,l,mid,pos); 15 else change(t[x].r,mid+1,r,pos); 16 t[x].s=t[t[x].l].s+t[t[x].r].s; 17 return; 18 } 19 int query(int x,int y,int l,int r,int L,int R) 20 { 21 if(l==L&&r==R)return t[y].s-t[x].s; 22 int mid=l+r>>1; 23 if(mid>=R)return query(t[x].l,t[y].l,l,mid,L,R); 24 else if(mid<L)return query(t[x].r,t[y].r,mid+1,r,L,R); 25 return query(t[x].l,t[y].l,l,mid,L,mid)+query(t[x].r,t[y].r,mid+1,r,mid+1,R); 26 } 27 int main() 28 { 29 scanf("%d",&n);int x,l,r; 30 for(int i=1;i<=n;++i) 31 { 32 scanf("%d",&x); 33 last[i]=pos[x]; 34 pos[x]=i; 35 } 36 for(int i=1;i<=n;++i)rt[i]=rt[i-1],change(rt[i],0,n,last[i]); 37 scanf("%d",&m); 38 for(int i=1;i<=m;++i) 39 { 40 scanf("%d%d",&l,&r); 41 printf("%d\n",query(rt[l-1],rt[r],0,n,0,l-1)); 42 } 43 return 0; 44 }