bzoj2743: [HEOI2012]采花
树状数组,离线处理。
首先把询问按左端点的大小升序排序。
从左往右扫描的过程中,将一个颜色第一次出现的位置变为0,第二次出现的位置变为1.
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 1000000 + 10; struct Query { int l,r,id; }q[maxn]; struct BIT { int a[maxn]; int n; inline int lowbit(int x) { return x&-x; } int query(int x) { int res=0; for(int i=x;i;i-=lowbit(i)) res+=a[i]; return res; } void add(int x,int val) { for(int i=x;i<=n;i+=lowbit(i)) a[i]+=val; } void init(int n2) { n=n2; memset(a,0,sizeof(a)); } }bit; bool cmp(Query a, Query b) { return a.l<b.l || (a.l==b.l && a.r<b.r); } int n,c,m,l; int a[maxn],next[maxn],p[maxn],ans[maxn]; int main() { scanf("%d%d%d",&n,&c,&m); bit.init(n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=n;i>=1;i--) { next[i]=p[a[i]]; p[a[i]]=i; } for(int i=1;i<=c;i++) if(next[p[i]]) bit.add(next[p[i]],1); for(int i=1;i<=m;i++) { scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } sort(q+1,q+m+1,cmp); l=1; for(int i=1;i<=m;i++) { while(l<q[i].l) { if(next[l]) bit.add(next[l],-1); if(next[next[l]]) bit.add(next[next[l]],1); l++; } ans[q[i].id]=bit.query(q[i].r)-bit.query(q[i].l-1); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }