📅  最后修改于: 2023-12-03 15:26:36.692000             🧑  作者: Mango
在程序开发中,经常需要查找具有更新的至少X值的[L,R]范围内的最小索引。以下是介绍查找具有更新的至少X值的[L,R]范围内的最小索引的一些重要信息和代码示例。
问题描述如下:
给定一个长度为N的序列A和一个整数X,查询满足如下要求的最小的i:
这个问题可以使用经典算法解决,时间复杂度为O(NlogN)。
离线查询的代码示例如下:
int N,M,cnt=0;
LL a[MAXN],o[MAXN],od[MAXN],idx[MAXN];
struct Query{int k,l,r,id;} Q[MAXM];
void add(int x,LL w,int d){for(;x<=N;x+=x&-x)o[x]+=w,od[x]+=d;}
LL get(int x){LL res=0,d=0;for(;x;x-=x&-x)res+=o[x],d+=od[x];return res-d*X;}
bool cmp(Query A,Query B){return A.r==B.r?A.k<B.k:A.r<B.r;}
int main(){
scanf("%d%d%d",&N,&M,&X);
for(int i=1;i<=N;i++)scanf("%lld",&a[i]);
for(int i=1;i<=M;i++){
Q[i].id=i;scanf("%d%d",&Q[i].l,&Q[i].r);Q[i].k=(Q[i].r-Q[i].l+1)/X;idx[i]=Q[i].l-1;
}
sort(Q+1,Q+M+1,cmp);
for(int i=1,j=1;i<=N;i++){
while(j<=M&&Q[j].r==i){
if(idx[Q[j].id]<Q[j].l)idx[Q[j].id]=Q[j].l-1;
for(int k=idx[Q[j].id]+1;k<=i;k++)add(a[k]+1,1,X-((i-k)/X));
idx[Q[j].id]=i,j++;
}
add(a[i]+1,-1,0);a[i]++,add(a[i]+1,1,0);
}
for(int i=1;i<=M;i++){
LL l=0,r=N-m,ll,rr;
while(l<=r){
LL mid=(l+r)>>1,x=get(Q[i].r)-get(mid-1);
if(x>=X)ll=mid,r=mid-1,rr=x;
else l=mid+1;
}
printf("%lld\n",Q[i].k*X+ll-1);
}
return 0;
}
主席树的代码示例如下:
int cur=0;
LL a[MAXN],nxt[MAXN],fir[MAXN],ver[MAXN],idx[MAXN],o[MAXN],od[MAXN],ans[MAXM];
struct Query{int k,l,r,id;} Q[MAXM];
struct Node{int l,r;LL s;}tr[MAXN*20];
int Build(int l,int r){
int t=++cur;tr[t].s=0;
if(l<r){int mid=(l+r)>>1;tr[t].l=Build(l,mid),tr[t].r=Build(mid+1,r);}
return t;
}
int Insert(int p,int l,int r,int x){
int t=++cur;memcpy(tr+t,tr+p,sizeof(Node));
if(l==r)tr[t].s=tr[p].s+1;
else{int mid=(l+r)>>1;if(x<=mid)tr[t].l=Insert(tr[p].l,l,mid,x);else tr[t].r=Insert(tr[p].r,mid+1,r,x);
tr[t].s=tr[tr[t].l].s+tr[tr[t].r].s;}
return t;
}
LL Query(int p,int l,int r,int x,int y){
if(!p||tr[p].s<=y-x)return 0;
if(l==r)return tr[p].s-y+l;
int mid=(l+r)>>1;
if(mid>=x)return Query(tr[p].l,l,mid,x,y)+(tr[tr[p].r].s-y+mid);
else return Query(tr[p].r,mid+1,r,x,y);
}
bool cmp(Query A,Query B){return A.r==B.r?A.k<B.k:A.r<B.r;}
int main(){
int N,M,X;scanf("%d%d%d",&N,&M,&X);
for(int i=1;i<=N;i++)scanf("%lld",&a[i]);
for(int i=1;i<=M;i++){
Q[i].id=i;scanf("%d%d",&Q[i].l,&Q[i].r);Q[i].k=(Q[i].r-Q[i].l+1)/X;
}
sort(Q+1,Q+M+1,cmp);
int rt=Build(1,N),cnt=0;
for(int i=1;i<=N;i++){
int x=a[i]+1;if(nxt[x])rt=Insert(rt,1,N,nxt[x]),add(fir[nxt[x]],-1),add(fir[nxt[x]]=i,1);
else rt=Insert(rt,1,N,nxt[x]=++cnt),fir[nxt[x]]=i;
while(ver[q[i].x]<cnt){ver[q[i].x]++;int y=idx[ver[q[i].x]];add(fir[x],-1),add(fir[x]=nxt[a[y]+1]=nxt[a[y]]+1,1);Insert(rt,1,N,nxt[a[y]+1]);}
for(int k=idx[ver[q[i].x]];k<=i;k++)tr[nxt[a[k]+1]]=Insert(tr[nxt[a[k]]],1,N,k),add(fir[nxt[a[k]]],-1),add(fir[nxt[a[k]+1]],1);
idx[ver[q[i].x]]=i;
for(int j=1;j<=M&&Q[j].r==i;j++){
int l=0,r=cnt,mn=X*Q[j].k;nxt[N+1]=0;
while(l<=r){
int mid=(l+r)>>1;
if(Query(tr[nxt[mid]],1,N,Q[j].l,i)>=mn)r=mid-1;
else l=mid+1;
}
ans[Q[j].id]=(l-1)*X+Q[j].l-1;
}
}
for(int i=1;i<=M;i++)printf("%lld\n",ans[i]);
return 0;
}
以上就是查找具有更新的至少X值的[L,R]范围内的最小索引的介绍和相关代码示例。