P1972 [SDOI2009]HH的项链
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
莫队的做法被卡了,所以刷一篇线段树的做法,由于是离线,限制并不算太多
把询问按照右端点排序,从序列左端点向右扫,进行三个操作:
$1$.将上一个与$c[i]$相同的点变为0
$2$.将这个点变为1
$3$.询问右端点固定的区间的答案
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define N 1000000 using namespace std; struct node{ int sum; }tr[N]; int c[N],last[N]; struct kpde{ int l,r,id,an; }p[N]; bool cmp(kpde A,kpde B){ return A.r<B.r; } bool ccmp(kpde A,kpde B){ return A.id<B.id; } void pushup(int k){ tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum; } void change(int k,int l,int r,int X,int val){ if(l==r){ tr[k].sum=val;return; } int mid=(l+r)>>1; if(X<=mid) change(k<<1,l,mid,X,val); else change(k<<1|1,mid+1,r,X,val); pushup(k); } int ask(int k,int l,int r,int ql,int qr){ if(l>=ql&&r<=qr) return tr[k].sum; int mid=(l+r)>>1,ans=0; if(ql<=mid) ans+=ask(k<<1,l,mid,ql,qr); if(qr>mid) ans+=ask(k<<1|1,mid+1,r,ql,qr); return ans; } int n,m; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&c[i]); scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d%d",&p[i].l,&p[i].r),p[i].id=i; sort(p+1,p+1+m,cmp); int now=1; for(int i=1;i<=n;i++){ if(last[c[i]]) change(1,1,n,last[c[i]],0); last[c[i]]=i; change(1,1,n,i,1); while(p[now].r==i){ p[now].an=ask(1,1,n,p[now].l,p[now].r); now++; } } sort(p+1,p+1+m,ccmp); for(int i=1;i<=m;i++) printf("%d ",p[i].an); return 0; }