题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6703
题意:
给一个数组
a
n
a_n
an,
a
i
∈
[
1
,
n
]
a_i∈[1,n]
ai∈[1,n],且各不相同
现在有两种操作:
①将
a
p
o
s
a_{pos}
apos加上
1
0
7
10^7
107
②查找满足大于等于
k
k
k且不等于
a
1
,
a
2
,
⋅
⋅
⋅
,
a
r
a_1,a_2,···,a_r
a1,a2,⋅⋅⋅,ar中的任意一个的最小值
这里得到的操作都要异或上次的答案
另外题目保证每次得到的
p
o
s
,
r
,
k
∈
[
1
,
n
]
pos, r, k∈[1,n]
pos,r,k∈[1,n]
题解:
显然是一道强制在线的题,要按顺序处理
需要注意的是,答案可以不是当前数列中的数,比如将
1
−
>
1
0
7
+
1
1->10^7+1
1−>107+1,然后查找大于1的且不等于
a
1
,
a
2
,
⋅
⋅
⋅
,
a
n
a_1,a_2,···,a_n
a1,a2,⋅⋅⋅,an的最小值,这里答案可以是1,并且可以得出 答案是在
[
1
,
n
+
1
]
[1,n+1]
[1,n+1] 的结论
由于每次得到的
p
o
s
,
r
,
k
∈
[
1
,
n
]
pos, r, k∈[1,n]
pos,r,k∈[1,n],因而每次操作后都不会变成答案,而且不管怎么操作,每个数都会是不一样的
这里有修改和区间内查询操作,显然是一道线段树题(比赛的时候想歪了,往动态主席树啥的想,一顿操作猛如虎,回首一看线段树,笨比至极)
先问题转化为:
求值在
[
k
,
n
+
1
]
[k,n+1]
[k,n+1]内并且坐标大于
r
r
r的最小值
我们用线段树节点本身代表的就是数值,每个点都记录当前区间
[
l
,
r
]
[l,r]
[l,r]内坐标的最大值
p
p
p,如果区间的最大坐标都小于
r
r
r 就没必要找了
所以在查找的时候,先找到
[
k
,
n
+
1
]
[k,n+1]
[k,n+1]的区间节点(下面的query),然后在这里面再找坐标大于
r
r
r的最小值(下面的find)
其中find函数需要一个剪枝,因为是找最小值,所以如果左子树找不到,才会找右子树,因为左子树数值更小
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define lc u<<1
#define rc u<<1|1
#define m (l+r)/2
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> Pair;
const int MAX = 2e5 + 10;
int T, N, M;
int a[MAX], pos[MAX];
struct SegTree {
int l, r, p;
}t[MAX << 2];
int ans;
void push_up(int u) {
t[u].p = max(t[lc].p, t[rc].p);
}
void build(int u, int l, int r) {
t[u].l = l, t[u].r = r;
if (l == r) {
t[u].p = pos[l];//记录坐标
return;
}
build(lc, l, m); build(rc, m + 1, r);
push_up(u);
}
void update(int u, int P) {
if (P < t[u].l || P > t[u].r)return;
if (t[u].l == t[u].r) {
t[u].p = N + 1;//将更新的节点都指向N+1
return;
}
update(lc, P); update(rc, P);
push_up(u);
}
void find(int u, int r) {//再找坐标大于r的最小值
if (t[lc].p > r)find(lc, r);
else if (t[rc].p > r)find(rc, r);//剪枝操作,左边找不到才去找右边
if (t[u].p > r && t[u].l == t[u].r)ans = min(ans, t[u].l);
}
void query(int u, int l, int r, int R) {//先找到[k,n+1]
if (t[u].l >= l && t[u].r <= r) {
find(u, R);
return;
}
int mid = (t[u].l + t[u].r) / 2;
if (l <= mid)query(lc, l, r, R);
if (r > mid)query(rc, l, r, R);
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; i++) {
scanf("%d", &a[i]);
pos[a[i]] = i;
}
pos[N + 1] = N + 1;
build(1, 1, N + 1);
ans = 0;//最初的ans为0
for (int i = 1; i <= M; i++) {
int op;
scanf("%d", &op);
if (op == 1) {
int n;
scanf("%d", &n); n ^= ans;
update(1, a[n]);
}
else {
int k, r;
scanf("%d%d", &r, &k); r ^= ans, k ^= ans;
ans = INF;
query(1, k, N + 1, r);
printf("%d\n", ans);
}
}
}
return 0;
}