这 里 要 用 到 权 值 线 段 树 , 因 为 题 目 保 证 了 a i 属 于 [ 1 , n ] , 且 不 重 复 。 这里要用到权值线段树,因为题目保证了a_i属于[1,n],且不重复。 这里要用到权值线段树,因为题目保证了ai属于[1,n],且不重复。 那 么 用 权 值 为 下 标 , 线 段 树 的 值 是 i , 即 原 序 列 的 下 标 。 那么用权值为下标,线段树的值是i,即原序列的下标。 那么用权值为下标,线段树的值是i,即原序列的下标。
题 目 可 以 转 化 为 求 解 [ k , n ] 中 , 第 一 个 线 段 树 的 值 大 于 r 的 下 标 是 多 少 题目可以转化为求解[k,n]中,第一个线段树的值大于r的下标是多少 题目可以转化为求解[k,n]中,第一个线段树的值大于r的下标是多少
不 存 在 的 情 况 输 出 n + 1 就 行 了 , 当 然 如 果 一 开 始 k > n 了 , 不存在的情况输出n+1就行了,当然如果一开始k>n了, 不存在的情况输出n+1就行了,当然如果一开始k>n了, 直 接 输 出 k 即 可 直接输出k即可 直接输出k即可
首 先 建 立 一 个 维 护 最 大 值 可 以 单 点 修 改 的 线 段 树 , 区 间 查 询 怎 么 写 首先建立一个维护最大值可以单点修改的线段树,区间查询怎么写 首先建立一个维护最大值可以单点修改的线段树,区间查询怎么写
就 是 这 道 题 目 的 精 髓 所 在 了 。 就是这道题目的精髓所在了。 就是这道题目的精髓所在了。
显 然 , 最 左 边 符 合 条 件 的 点 就 是 答 案 。 显然,最左边符合条件的点就是答案。 显然,最左边符合条件的点就是答案。
优 先 遍 历 左 子 树 , 若 左 子 树 中 存 在 答 案 , 结 束 查 询 ; 若 不 存 在 , 则 优先遍历左子树,若左子树中存在答案,结束查询;若不存在,则 优先遍历左子树,若左子树中存在答案,结束查询;若不存在,则
查 询 右 子 树 。 直 接 这 样 做 , 单 次 查 询 其 实 是 O ( n ) 的 , 需 要 进 行 减 枝 。 查询右子树。直接这样做,单次查询其实是O(n)的,需要进行减枝。 查询右子树。直接这样做,单次查询其实是O(n)的,需要进行减枝。
每 次 查 询 一 颗 子 树 前 先 取 其 最 大 值 与 r 比 较 , 小 于 等 于 r 就 可 以 跳 过 每次查询一颗子树前先取其最大值与r比较,小于等于r就可以跳过 每次查询一颗子树前先取其最大值与r比较,小于等于r就可以跳过
这 个 子 树 了 , 而 最 大 值 在 单 点 修 改 时 是 维 护 好 的 , 现 在 的 调 用 是 O ( 1 ) 这个子树了,而最大值在单点修改时是维护好的,现在的调用是O(1) 这个子树了,而最大值在单点修改时是维护好的,现在的调用是O(1)
的 , 所 以 整 个 查 询 的 复 杂 度 是 O ( l o g n ) 的 。 的,所以整个查询的复杂度是O(logn)的。 的,所以整个查询的复杂度是O(logn)的。
至 于 单 点 修 改 , 就 是 将 那 个 权 值 的 节 点 修 改 为 任 意 大 于 1 0 5 的 值 即 可 。 至于单点修改,就是将那个权值的节点修改为任意大于10^5的值即可。 至于单点修改,就是将那个权值的节点修改为任意大于105的值即可。
#include
#define ll long long
using namespace std;
const int maxn = 1e5+10;
const int inf = 1e9+7;
int T;
int n,m;
ll ans;
int arr[maxn],a[maxn];
struct TREE{
int id;
int v;
}tree[(maxn<<2)+10];
void build(int l,int r,int index){
if(l==r){
tree[index].id=a[l];
tree[index].v=l;
}
else{
int mid=l+((r-l)>>1);
build(l,mid,index<<1);
build(mid+1,r,(index<<1)|1);
if(tree[index<<1].id>tree[(index<<1)|1].id){
tree[index].id=tree[index<<1].id;
tree[index].v=tree[index<<1].v;
}
else{
tree[index].id=tree[(index<<1)|1].id;
tree[index].v=tree[(index<<1)|1].v;
}
}
}
void update(int dis,int l,int r,int index,int val){
if(l==r){
tree[dis].id=val;
return ;
}
int mid=l+((r-l)>>1);
if(index<=mid)
update(dis<<1,l,mid,index,val);
else
update((dis<<1)|1,mid+1,r,index,val);
if(tree[dis<<1].id>tree[(dis<<1)|1].id){
tree[dis].id=tree[dis<<1].id;
tree[dis].v=tree[dis<<1].v;
}
else{
tree[dis].id=tree[(dis<<1)|1].id;
tree[dis].v=tree[(dis<<1)|1].v;
}
}
int query(int dis,int l,int r,int ql,int qr,int val){
if(ql>r||qr<l)return -1;
if(l==r){
if(tree[dis].id>val)
return tree[dis].v;
else return -1;
}
int res,mid=l+((r-l)>>1);
if(tree[dis<<1].id>val)
res=query(dis<<1,l,mid,ql,qr,val);
else
res=-1;
if(res!=-1)return res;
else{
if(tree[(dis<<1)|1].id>val)
res=query((dis<<1)|1,mid+1,r,ql,qr,val);
else return -1;
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
a[arr[i]]=i;
}
build(1,n,1);
int flag;
int t1,r,k;
for(int i=1;i<=m;i++){
scanf("%d",&flag);
if(flag==1){
scanf("%d",&t1);
t1=t1^ans;
update(1,1,n,arr[t1],inf);
}
else{
scanf("%d%d",&r,&k);
r=r^ans;k=k^ans;
if(k>n)ans=k;
else {
int res=query(1,1,n,k,n,r);
if(res==-1)ans=n+1;
else ans=res;
}
printf("%d\n",ans);
}
}
}
return 0;
}