#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int tot,n,m,ver[maxn];
struct tt{
int l,r,val;
//val:某个时间(ver)下 该树内所有数都出现的 最后位置
}tree[maxn<<5];
int build(int l,int r){
int rt=++tot;
tree[rt].val=0;
tree[rt].l=rt;
tree[rt].r=rt;
return rt;
}
void pushup(int root){
tree[root].val=min(tree[tree[root].l].val,tree[tree[root].r].val);
//要以root为根的树下的所有数都出现,都所以取min
}
int change(int node,int l,int r,int x,int p){
//x在p位置上出现
//xlr是数,p是状态时间位置
int root=++tot;
tt &rt=tree[root];
rt=tree[node];
//找到x的"位置"了
if(l==r){
rt.val=p;
//因为每次change是按时间序来的,所以就p是x在该时刻最晚出现的位置
return root;
}
int mid=(l+r)>>1;
if(x<=mid) rt.l=change(rt.l,l,mid,x,p);
else rt.r=change(rt.r,mid+1,r,x,p);
pushup(root);
return root;
}
int query(int node,int L,int R,int l,int r){
if(l==r) return l;
tt &rt=tree[node];
tt &rl=tree[rt.l],&rr=tree[rt.r];
int mid=(l+r)>>1;
//左边的数都出现的最晚位置>=L,说明左边数都出现了。右边同理
//<L,就说明还有数没出现过。因为要求最小的没出现过的,所以先判断左再判断右
if(rl.val<L) return query(rt.l,L,R,l,mid);
else if(rr.val<L) return query(rt.r,L,R,mid+1,r);
else return n;//左右都>=L说明全出现过了。就返回n
}
int main(){
int t,x,L,R;
cin>>t;
while(t--){
tot=0;
scanf("%d%d",&n,&m);
ver[0]=build(0,n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
x=x>n?n:x;//>n的数用n代替,因为题目只考虑0~n-1这些数是否出现,其它数可一律看做n
ver[i]=change(ver[i-1],0,n,x,i);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&L,&R);
printf("%d\n",query(ver[R],L,R,0,n));
//用R时刻的树来看,将其最晚位置和L比较
}
}
return 0;
}
zjhu1021mex函数(可持久线段树)
最新推荐文章于 2024-10-09 22:28:58 发布
本文介绍了一种使用C++编程语言实现的数据结构,通过构建二叉搜索树并维护每个节点的时间范围,解决在给定时间段内查找所有元素是否出现的问题。重点讲解了`build`、`change`和`query`函数,适用于实时查询和更新数据的场景。
摘要由CSDN通过智能技术生成