题目链接。题意有点绕,但是仔细读一下还是可以读出来的。给一个数组a,数组元素是n的排列,长度1e5,然后两种操作.
1.(1,pos)。把a[pos]给变成a[pos]+1e7
2.(2,r,k)。询问大于等于k的一个数,并且这个数不能等于a[1,r]区间内的任意一个数。1<=k<=n。
询问1e5次。
额,上来看觉得主席树轻松秒,然后查询树上二分。其实就是再权值数组上操作。因为主席树天生自带一个log再加上树上二分一个log,nlogn^2.TLE.仔细思考了一下,发现没必要主席树。
分析:
首先,还是用数组b[i]=j,代表数组中的i的当前位置是j。
(1)如果是操作1,那么这个数就没用了,因为它被加了一个很大的数上去,已经不再这个数组里。那么可以给他一个INF,其实没必要INF,n+1就够了,下面说为什么n+1就行。
(2)对于每个查询,答案最大是n+1,因为r<=n,所以在[1,r]中的元素不会超过n,那么最大的不等于[1,n]中的所有元素的值就是n+1.所以当一个数被修改后,可以直接把b数组里这个数对应的值改为n+1.即可。那么怎么通过b数组找答案呢?对于每个查询,其实我们需要的是[x,n]这个区间内,第一个出现的数字,并且这个数字在b数组对应的值要大于r。解释一下就是,在[x,n]这个区间内,从x一直向右走,遇到一个元素,检查它的在b数组里的值,在b数组里的值其实也就是他在元素组中的下标,如果这个下标<r,说明这个值在[1,r]之间,不是我们想要的,继续向前走。分析到这里,其实做法就显然了,对b数组建立线段树,节点维护当前区间所有数下标的最大值,这棵树也是一颗权值线段树。查询贪心的查左子树,如果左子树可行,就往左子树跑,检查的规则就是看一下当前子树节点的存的哪个最大值是不是大于r,如果不是,那么说明这段区间是不可行的,否则可以递归下去找到产生最大值得那个点,然后因为可能会找到几个满足条件点,所以在儿子返回结果时,也就是回溯回来,在这些结果里取一个最小值作为答案。本题结束。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m;
int a[MAXN], b[MAXN];
int pos[MAXN << 2];
void pushup(int rt) {
pos[rt] = max(pos[rt << 1], pos[rt << 1 | 1]);
}
void build(int l, int r, int rt) {
if (l == r) {
pos[rt] = b[l];
return;
}
int mid = l + r >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int k, int l, int r, int rt) {
if (l == r) {
pos[rt] = n + 1;
return;
}
int mid = l + r >> 1;
if (k <= mid) update(k, l, mid, rt << 1);
else update(k, mid + 1, r, rt << 1 | 1);
pushup(rt);
}
int query(int ql, int qr, int k, int l, int r, int rt) {
int mid = l + r >> 1;
if (ql <= l && qr >= r) {
if (l == r) {
if (pos[rt] > k) return l;
else return n + 1;
}
if (pos[rt << 1] > k) return query(ql, qr, k, l, mid, rt << 1);
if (pos[rt << 1 | 1] > k) return query(ql, qr, k, mid + 1, r, rt << 1 | 1);
return n + 1;
}
if (qr <= mid) return query(ql, qr, k, l, mid, rt << 1);
if (ql > mid) return query(ql, qr, k, mid + 1, r, rt << 1 | 1);
return min(query(ql, qr, k, l, mid, rt << 1), query(ql, qr, k, mid + 1, r, rt << 1 | 1));
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int las = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[a[i]] = i;
build(1, n, 1);
for (int i = 1; i <= m; i++)
{
int opt, x, y;
scanf("%d%d", &opt, &x); x ^= las;
if (opt == 1) update(a[x], 1, n, 1);
else
{
scanf("%d", &y); y ^= las;
int curans = query(y, n, x, 1, n, 1);
printf("%d\n", curans);
las=curans;
}
}
}
return 0;
}