[BZOJ1878][SDOI2009]HH的项链解题报告
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。
Input
第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。
Output
M行,每行一个整数,依次表示询问对应的答案。
Sample Input6
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
2
4
看到题目,首先确定这是区间问题。然后考虑到不满足区间加减,于是考虑变形。
我们从左到右维护前缀和,表示在此前有多少个不同的。这个很容易用树状数组实现。
然后考虑到我们从左到右维护时,问题不一定从左到右,但这时离线的,我们就能排序后继续做。
维护到第i位,对于每一个r在i上的询问,它的答案等于Sr-S(l-1).
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline void read(int &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } int N,Q,arr[500005]; int tree[500005]; int ahead[1000005]; int ans[500005]; struct question{ int l,r,num; }que[500005]; int lowbit(int x) { return x&(-x); } void update(int x,int p) { for(int i=p;i<=N;i+=lowbit(i)) tree[i]+=x; } int query(int p) { int ans=0; for(int i=p;i>0;i-=lowbit(i)) ans+=tree[i]; return ans; } bool cmp1(question a,question b) { return a.r<b.r; } bool cmp2(question a,question b) { return a.num<b.num; } int main() { read(N); for(int i=1;i<=N;i++) read(arr[i]); read(Q); for(int i=1;i<=Q;i++) { read(que[i].l); read(que[i].r); que[i].num=i; } sort(que+1,que+Q+1,cmp1); int ques=1; for(int i=1;i<=N;i++) { if(!ahead[arr[i]]){ ahead[arr[i]]=i; update(1,i); } else{ update(-1,ahead[arr[i]]); update(1,i); ahead[arr[i]]=i; } while(ques<=Q){ if(que[ques].r==i) { ans[que[ques].num]=query(que[ques].r)-query(que[ques].l-1); ques++; } else break; } } for(int i=1;i<=Q;i++) printf("%d\n",ans[i]); }