题意:长为1e5的全排列 有两个操作 把一个数删掉
询问1,r这个区间内 找到一个数大于等于x 且这个数不等于区间内的所有数
题解:建一颗权值线段树 线段树里存值为i的数在原数组中的坐标 维护坐标的最大值
考虑删除操作 就等于让他的坐标变为n+1 因为答案一定在1-n+1
对于查询操作 等价于找在[x,n]这个权值区间内左边第一个出现的数 且他的坐标是大于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; printf("%d\n", las = query(y, n, x, 1, n, 1)); } } } return 0; }View Code