hdu6703

###name array

###descirption You are given an array \(a_1,a_2,...,a_n(∀i∈[1,n],1≤a_i≤n)\). Initially, each element of the array is unique.

Moreover, there are m instructions.

Each instruction is in one of the following two formats:

  1. (1,pos),indicating to change the value of \(a_{pos}\) to \(a_{pos}+10,000,000\);
  2. (2,r,k),indicating to ask the minimum value which is not equal to any \(a_i\) ( 1≤i≤r ) and not less than k.

Please print all results of the instructions in format 2.

###input The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, there are two integers n(1≤n≤100,000),m(1≤m≤100,000) in the first line, denoting the size of array a and the number of instructions.

In the second line, there are n distinct integers \(a_1,a_2,...,a_n (∀i∈[1,n],1≤a_i≤n)\),denoting the array. For the following m lines, each line is of format \((1,t_1) or (2,t_2,t_3)\). The parameters of each instruction are generated by such way :

For instructions in format 1 , we defined \(pos=t_1⊕LastAns\) . (It is promised that 1≤pos≤n)

For instructions in format 2 , we defined \(r=t_2⊕LastAns,k=t_3⊕LastAns\). (It is promised that 1≤r≤n,1≤k≤n )

(Note that ⊕ means the bitwise XOR operator. )

Before the first instruction of each test case, LastAns is equal to 0 .After each instruction in format 2, LastAns will be changed to the result of that instruction.

(∑n≤510,000,∑m≤510,000 )

###output For each instruction in format 2, output the answer in one line.

###sample input 3 5 9 4 3 1 2 5 2 1 1 2 2 2 2 6 7 2 1 3 2 6 3 2 0 4 1 5 2 3 7 2 4 3 10 6 1 2 4 6 3 5 9 10 7 8 2 7 2 1 2 2 0 5 2 11 10 1 3 2 3 2 10 10 9 7 5 3 4 10 6 2 1 8 1 10 2 8 9 1 12 2 15 15 1 12 2 1 3 1 9 1 12 2 2 2 1 9

###sample output 1 5 2 2 5 6 1 6 7 3 11 10 11 4 8 11

###hint note: After the generation procedure ,the instructions of the first test case are : 2 1 1, in format 2 and r=1 , k=1 2 3 3, in format 2 and r=3 , k=3 2 3 2, in format 2 and r=3 , k=2 2 3 1, in format 2 and r=3 , k=1 2 4 1, in format 2 and r=4 , k=1 2 5 1, in format 2 and r=5 , k=1 1 3 , in format 1 and pos=3 2 5 1, in format 2 and r=5 , k=1 2 5 2, in format 2 and r=5 , k=2

the instructions of the second test case are : 2 7 2, in format 2 and r=7 , k=2 1 5 , in format 1 and pos=5 2 7 2, in format 2 and r=7 , k=2 2 8 9, in format 2 and r=8 , k=9 1 8 , in format 1 and pos=8 2 8 9, in format 2 and r=8 , k=9

the instructions of the third test case are : 1 10 , in format 1 and pos=10 2 8 9 , in format 2 and r=8 , k=9 1 7 , in format 1 and pos=7 2 4 4 , in format 2 and r=4 , k=4 1 8 , in format 1 and pos=8 2 5 7 , in format 2 and r=5 , k=7 1 1 , in format 1 and pos=1 1 4 , in format 1 and pos=4 2 10 10, in format 2 and r=10 , k=10 1 2 , in format 1 and pos=2

###toturial1 先不考虑修改,若只有查询,我们发现每次都是前缀的查询,这里显然是可以使用主席树用log的复杂度完成的,然后我们考虑修改,我们发现修改等价于删除数字,那么这样一来,又因为每个数都是独一无二的,删除只会让答案变得更小,且恰好变成删掉的数字,我们可以尝试用一个集合记录所有删掉的数字,然后用lower_bound来查询,和主席树得到的答案取得最小值,就是真正的答案。证明过程很简单,分类证明即可。

###code1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 主席树+set
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=int(k);++i)

inline int read(){int x;scanf("%d",&x);return x;}

const int maxn = 1e5+5;
int ls[maxn*20*1],rs[maxn*20*1],siz[maxn*20*1],tot,rt[maxn];//update用了几次,就要乘以多少
void update(int pre,int&u,int l,int r,int pos,int val){//把u按照pre复制,然后更新pos
u=++tot;
ls[u]=ls[pre];rs[u]=rs[pre];
siz[u]=siz[pre]+val;
if(l==r)return ;
int mid=(l+r)>>1;
if(pos<=mid) update(ls[pre],ls[u],l,mid,pos,val);
else update(rs[pre],rs[u],mid+1,r,pos,val);
}

int query(int u,int l,int r,int ql,int qr){
int mid=(l+r)>>1,res=1e9;
if(ql<=l&&r<=qr){
if(l==r)return siz[u]==0?l:1e9;
if(siz[ls[u]]!=mid-l+1) return query(ls[u],l,mid,ql,qr);
else return query(rs[u],mid+1,r,ql,qr);
}
if(ql<=mid)res=min(res,query(ls[u],l,mid,ql,qr));
if(res!=1e9)return res;
if(qr>=mid+1)res=min(res,query(rs[u],mid+1,r,ql,qr));
return res;
}

int a[maxn];
int main(){
int T=read();
rep(times,1,T){
tot=0;
set<int>se;
se.insert(1e9);
int n=read(),m=read();
rep(i,1,n) update(rt[i-1],rt[i],1,n+1,a[i]=read(),1);
int lastans=0;
rep(i,1,m){
if(read()==1) se.insert(a[read()^lastans]);
else{
int r=read()^lastans,k=read()^lastans;
printf("%d\n",lastans=min(*se.lower_bound(k),query(rt[r],1,n+1,k,n+1)));
}
}
}
}

###toturial2 逆向思维,反转键值,题目让我们在键区间[1,r]上找到最小的不小于k的值,我们反转后变成了在值区间[k,n+1]上找到值最小的键,其键不小于k,修改操作就成了把值所对的键修改为无穷大,这个问题用普通最值线段树很轻松就能解决

###code2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 逆向思维 键值颠倒
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=int(k);++i)

inline int read(){int x;scanf("%d",&x);return x;}

#define ml ((l+r)>>1)
#define mr (ml+1)
const int maxn = 1e5+20;
int ls[maxn*2],rs[maxn*2],mx[maxn*2],a[maxn],pos[maxn],tot;//update用了几次,就要乘以多少
void build(int&u,int l,int r){
u=++tot;
if(l==r) {mx[u]=pos[l];return;}
build(ls[u],l,ml);
build(rs[u],mr,r);
mx[u]=max(mx[ls[u]],mx[rs[u]]);
}

void update(int&u,int l,int r,int q,int d){
if(l==r) {mx[u]=d;return;}
if(q<=ml) update(ls[u],l,ml,q,d);
else update(rs[u],mr,r,q,d);
mx[u]=max(mx[ls[u]],mx[rs[u]]);
}

int query(int u,int l,int r,int ql,int qr,int x){// >x
int ans=1e9;
if(ql<=l&&r<=qr){
if(mx[u]<=x) return 1e9;
if(l==r) return l;
ans=query(ls[u],l,ml,ql,qr,x);
if(ans!=1e9) return ans;
return query(rs[u],mr,r,ql,qr,x);
}
if(ml>=ql) ans=min(ans,query(ls[u],l,ml,ql,qr,x));
if(ans!=1e9) return ans;
if(mr<=qr) ans=min(ans,query(rs[u],mr,r,ql,qr,x));
return ans;
}

int main(){
int T=read();
rep(times,1,T){
tot=0;
int n=read(),m=read(),rt;
rep(i,1,n) a[i]=read(),pos[a[i]]=i;
a[n+1]=n+1,pos[n+1]=n+1;
build(rt,1,n+1);
int lastans=0;
rep(i,1,m){
if(read()==1) {
int val=a[read()^lastans];
update(rt,1,n+1,val,n+1);
// pos[val]=n+1;
}
else{
int r=read()^lastans,k=read()^lastans;
printf("%d\n",lastans=query(rt,1,n+1,k,n+1,r));
// rep(i,k,n+1) if(pos[i]>r) {cout<<" "<<i<<endl;lastans=i;break;}
}
}
}
}