C91 树状数组+排序 P1972 [SDOI2009] HH的项链
视频链接:C91 树状数组+排序 P1972 [SDOI2009] HH的项链_哔哩哔哩_bilibili
C35 线段树+排序 P1972 [SDOI2009] HH的项链 - 董晓 - 博客园 (cnblogs.com)
C52 可持久化线段树 P1972 [SDOI2009] HH的项链 - 董晓 - 博客园 (cnblogs.com)
// 树状数组+排序 O(nlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; void read(int &x){ x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); } #define N 1000010 #define lowb(x) x&-x int n,m; int a[N],last[N],ans[N]; int s[N]; //区间内1的个数 struct Q{ int l,r,id; //查询的区间端点,查询的编号 bool operator<(const Q& b)const{ return r<b.r; } }q[N]; void change(int x,int k){ //向后修 while(x<=n) s[x]+=k, x+=lowb(x); } int query(int x){ //向前查 int t=0; while(x) t+=s[x], x-=lowb(x); return t; } int main(){ read(n); for(int i=1;i<=n;++i) read(a[i]); read(m); for(int i=1;i<=m;++i) read(q[i].l),read(q[i].r),q[i].id=i; sort(q+1,q+m+1); //查询按右端点排序 for(int i=1,lp=1;i<=m;++i){ //枚举每个查询 for(int j=lp;j<=q[i].r;++j){ //枚举右端点前面的位置 if(last[a[j]]) change(last[a[j]],-1); //aj上次位置-1 change(j,1); //aj这次的位置+1 last[a[j]]=j; //记录aj这次的位置 } lp=q[i].r+1; //更新已处理位置的左边界 ans[q[i].id]=query(q[i].r)-query(q[i].l-1); //记录答案 } for(int i=1;i<=m;++i) printf("%d\n",ans[i]); }