C92 树状数组+排序 P4113 [HEOI2012] 采花
视频链接:C92 树状数组+排序 P4113 [HEOI2012] 采花_哔哩哔哩_bilibili
// 树状数组+排序 O(nlogn) #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 2000010 #define lowb(x) x&-x int n,c,m,a[N],pos1[N],pos2[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(){ scanf("%d%d%d",&n,&c,&m); for(int i=1;i<=n;++i)scanf("%d",&a[i]); 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); //查询按右端点排序 for(int i=1,j=1;i<=m;++i){ //枚举每个查询 for(;j<=q[i].r;++j){ //枚举r前面的位置 if(!pos1[a[j]]) //若aj第1次位置为空 pos1[a[j]]=j; //记录aj第1次出现位置 else{ //若aj第1次位置不空 if(!pos2[a[j]]){ //若aj第2次位置为空 change(pos1[a[j]],1); //aj第1次出现位置+1 pos2[a[j]]=j; //记录aj第2次出现位置 } else{ //若aj第2次位置不空 change(pos1[a[j]],-1); //aj第1次出现位置清空 change(pos2[a[j]],1); //aj第2次出现位置+1 pos1[a[j]]=pos2[a[j]]; //第2次位置变成第1次 pos2[a[j]]=j; //当前位置变成第2次 } } } 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]); }