题目链接:
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;
}