2019CCPC网络选拨赛1002
这
里
要
用
到
权
值
线
段
树
,
因
为
题
目
保
证
了
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<bits\stdc++.h>
#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;
}