权值线段树保存历史版本
然后直接在树上二分
离散化的时候要注意
根据不同情况
要手动二分以及特殊情况的判别
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int R[N],A[N],cnt;
vector<int> V;
struct HisTree{
int l,r,sum;
}T[N*20];
int getid(int x){
int l=0,r=V.size()-1;
while(l<r){
int mid=(l+r+1)/2;
if(V[mid]<=x)l=mid;
else r=mid-1;
}
return l+1;
}
void build(int l,int r,int &x,int y,int pos){
T[++cnt]=T[y],x=cnt,T[x].sum++;
if(l==r)return;
int mid=(l+r)/2;
if(pos<=mid)build(l,mid,T[x].l,T[y].l,pos);
else build(mid+1,r,T[x].r,T[y].r,pos);
}
int ask(int l,int r,int x,int z){
if(l==r)return T[x].sum;
int mid=(l+r)/2;
if(z<=mid)return ask(l,mid,T[x].l,z);
else return T[T[x].l].sum+ask(mid+1,r,T[x].r,z);
}
int main(){
int TT;
cin>>TT;
for(int flag=1;flag<=TT;++flag){
int n,m;
cin>>n>>m;
V.clear();
memset(T,0,sizeof T);
cnt=0;
memset(R,0,sizeof R);
for(int i=1;i<=n;++i)scanf("%d",&A[i]),V.push_back(A[i]);
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
for(int i=1;i<=n;++i)build(1,n,R[i],R[i-1],getid(A[i]));
printf("Case %d:\n",flag);
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z<V[0])printf("0\n");
else printf("%d\n",ask(1,n,R[y+1],getid(z))-ask(1,n,R[x],getid(z)));
}
}
}