bzoj 1878: [SDOI2009]HH的项链 ——树状数组+ 差分
Description
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
Input
第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。
Output
M行,每行一个整数,依次表示询问对应的答案。
Sample Input
6
1 2 3 4 3 5
3
1 2
3 5
2 6
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
2
4
2
4
————————————————————————————————
这道题我们维护一下每个点的pre[i]
View Code
即对于每个位置i,预处理出pre[i]表示i左边离i最近的j 使得a[i]==a[j]
然后我们枚举右端点 维护一下每个左端点的答案就可以辣
即扫到一个点i的时候 s[pre[i]]-- s[i]++ 维护一下树状数组的差分就行了
因为你当前往前必然包含这个点 所以前面的区间的同一颜色的位置对当前以及后面的区间都没有任何影响了
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> const int M=1e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,k; int ans[5*M],last[15*M],pre[15*M],s[M]; struct pos{int x,id;}; std::vector<pos>q[M]; int l,r; #define lowbit(x) x&-x void ins(int x,int v){while(x<=n) s[x]+=v,x+=lowbit(x);} int query(int x){ int sum=0; while(x) sum+=s[x],x-=lowbit(x); return sum; } int main(){ n=read(); for(int i=1;i<=n;i++){ k=read(); if(last[k]) pre[i]=last[k]; last[k]=i; } m=read(); for(int i=1;i<=m;i++) l=read(),r=read(),q[r].push_back((pos){l-1,i}); for(int i=1;i<=n;i++){ if(pre[i]) ins(pre[i],-1); ins(i,1); int mx=q[i].size(),now=query(i); for(int j=0;j<mx;j++){ int x=q[i][j].x; ans[q[i][j].id]=now-query(x); } } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }