C91 树状数组+排序 P1972 [SDOI2009] HH的项链

视频链接:C91 树状数组+排序 P1972 [SDOI2009] HH的项链_哔哩哔哩_bilibili

 

 

 

C35 线段树+排序 P1972 [SDOI2009] HH的项链 - 董晓 - 博客园 (cnblogs.com)

C52 可持久化线段树 P1972 [SDOI2009] HH的项链 - 董晓 - 博客园 (cnblogs.com)

Luogu P1972 [SDOI2009] HH的项链

// 树状数组+排序 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]);
}

 

posted @ 2024-01-14 16:26  董晓  阅读(309)  评论(0编辑  收藏  举报