题意:
给出个数,求 ,这两个区间不同数的个数
思路:
其实只要把区间扩大一倍,就是求这个区间了
定义数组中第一次出现的数的后缀为,第次出现的数的后缀为该数第次出先时的下标。比如:原数组为,扩大一倍后为,每个数对应的后缀为。
如果某个数出现多次,而我们只算最右边的那个,我们会发现最右边的那个数的后缀一定是大于区间右端点的,其它的数的后缀一定是小于等于区间右端点的,所以我们只要把后缀大于区间右端点的数的下标取出来,然后用树状数组计算区间内有多少个数。
code;
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5+7; int head[maxn],c[maxn],Next[maxn],ans[maxn]; struct node { int l,r,x,id; bool operator<(const node& b)const { if(x!=b.x) return x>b.x; else if(id!=b.id) return id>b.id; else return l<b.l; } }; vector<node>v; int sum[maxn],m; inline void add(int p,int v) { while(p<=m) { sum[p]+=v; p+=(p&-p); } } inline int query(int p) { int res(0); while(p) { res+=sum[p]; p-=(p&-p); } return res; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); int n,Q; while(cin>>n>>Q) { for(int i=1; i<=n; ++i) cin>>c[i],c[i+n]=c[i]; m=n*2; for(int i=m; i; --i) { if(!head[c[i]]) Next[i]=m+1; else Next[i]=head[c[i]]; head[c[i]]=i; v.emplace_back(node {i,0,Next[i],0}); } for(int i=1,l,r; i<=Q; ++i) { cin>>l>>r; v.emplace_back(node {r,n+l,n+l,i}); } sort(v.begin(),v.end()); for(node i:v) { if(!i.id) add(i.l,1); else ans[i.id]+=query(i.r)-query(i.l-1); } for(int i=1; i<=Q; ++i) { cout<<ans[i]<<'\n'; ans[i]=0; } for(node i:v) if(!i.id) add(i.l,-1); for(int i=1; i<=n; ++i) head[c[i]]=0; v.clear(); } return 0; }