C35 线段树+排序 P1972 [SDOI2009] HH的项链

视频链接:C35 线段树+排序 P1972 [SDOI2009] HH的项链_哔哩哔哩_bilibili

 

 

Luogu P1972 [SDOI2009] HH的项链

// 线段树+排序
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

#define N 1000005
#define ls u<<1
#define rs u<<1|1
int n,m;
struct tree{
  int l,r,sum;
}tr[N*4];   //线段树
struct node{
  int l,r,id;
  bool operator<(node &b){
    return r<b.r;
  }
}q[N];      //查询
vector<int> v[N]; //右端点相同的查询
int a[N],last[N],ans[N];

void pushup(int u){ //上传
  tr[u].sum=tr[ls].sum+tr[rs].sum;
}
void build(int u,int l,int r){ //建树
  tr[u]={l,r,1};
  if(l==r) return;
  int m=l+r>>1;
  build(ls,l,m);
  build(rs,m+1,r);
  pushup(u);
}
void change(int u,int x){ //点修
  if(tr[u].l==x&&tr[u].r==x){
    tr[u].sum=0; return;
  }
  int m=tr[u].l+tr[u].r>>1;
  if(x<=m) change(ls,x);
  else change(rs,x);
  pushup(u);
}
int query(int u,int x,int y){ //区查
  if(x>tr[u].r || y<tr[u].l) return 0;
  if(x<=tr[u].l&&tr[u].r<=y) return tr[u].sum;
  return query(ls,x,y)+query(rs,x,y);
}
// int query(int u,int x,int y){ //区查
//   if(x<=tr[u].l&&tr[u].r<=y) return tr[u].sum;
//   int m=tr[u].l+tr[u].r>>1;
//   if(y<=m) return query(ls,x,y);
//   if(x>m) return query(rs,x,y);
//   return query(ls,x,m)+query(rs,m+1,y);
// }
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  scanf("%d",&m);
  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;i<=m;i++)
    v[q[i].r].push_back(i); //右端点相同的查询
  
  build(1,1,n);
  for(int i=1;i<=n;i++){ //枚举每个数
    if(last[a[i]]) change(1,last[a[i]]);
    last[a[i]]=i; //记录ai最后一次的下标
    
    for(auto t : v[i]) //处理右端点i的查询
      ans[q[t].id]=query(1,q[t].l,q[t].r);
  }
  for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
  return 0;
}

 

posted @ 2023-09-24 10:28  董晓  阅读(239)  评论(0编辑  收藏  举报