C92 树状数组+排序 P4113 [HEOI2012] 采花

视频链接:C92 树状数组+排序 P4113 [HEOI2012] 采花_哔哩哔哩_bilibili

 

 

Luogu P4113 [HEOI2012] 采花

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

 

posted @ 2024-01-15 16:23  董晓  阅读(141)  评论(1编辑  收藏  举报