题意:
给定一个1-n的排列,两种操作
1. (1,pos),indicating to change the value of apos to apos+10,000,000;
2. (2,r,k),indicating to ask the minimum value which is **not equal** to any ai ( 1≤i≤r ) and **not less ** than k.
查找不等于a[1] - a[r]间任何元素的且大于等于k的最小值
解题思路:
k数据范围为1e5 操作1加了1e7
所以2操作的最大答案就是n + 1,因为1-n排列的任意值+1e7都完全大于n + 1
这样考虑,如果一个数字+1e7了,说明这个值已经不在这个排列之中了,所以可以直接使用作为答案
那么问题分解为查找一个最接近k的元素不等于1-r之中任意元素或r + 1 到 n + 1之间任意元素
那么可以保存一个set记录不在排列中的值
用可持久线段树查r + 1 到 n + 1之中大于等于k的第一个元素(必然可以使用)
或已经+1e7的元素(必然可以使用即可)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 100;
int root[MAXN], tot = 0;
struct node
{
int ls, rs, val;
}t[MAXN << 5];
void update(int l, int r, int &now, int lst, int pos)
{
now = ++tot;
t[now] = t[lst];
++t[now].val;
if(l == r) { return ; }
int mid = (l + r) >> 1;
if(pos <= mid) update(l, mid, t[now].ls, t[lst].ls, pos);
else update(mid + 1, r, t[now].rs, t[lst].rs, pos);
}
int fp = 0;
void find(int l, int r, int now, int pos)
{
if(r < pos || l >= fp)
return ;
if(l == r)
{
fp = min(fp, l);
return ;
}
int mid = (l + r) >> 1;
if(pos <= mid && t[t[now].ls].val)
find(l, mid, t[now].ls, pos);
if(t[t[now].rs].val)
find(mid + 1, r, t[now].rs, pos);
}
int arr[MAXN] = {0};
void init(int n)
{
memset(root, 0, sizeof(root));
tot = 0;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T, n, m;
cin >> T;
while(T--)
{
cin >> n >> m;
for(int i = 1; i <= n; ++i)
cin >> arr[i];
init(n);
update(1, n + 1, root[n + 1], root[n + 2], n + 1);
set <int> ST;
ST.insert(n + 1);
for(int i = n; i >= 1; --i)
update(1, n + 1, root[i], root[i + 1], arr[i]);
int lans = 0;
while(m--)
{
int opt, pos, t1, t2, t3, r, k;
cin >> opt;
if(opt == 1)
{
cin >>t1;
t1 ^= lans;
ST.insert(arr[t1] );
}
else
{
cin >> t2 >> t3;
t2 ^= lans; t3 ^= lans;
//cout << t2 << ' ' << t3 << '
';
fp = n + 1;
find(1, n + 1, root[t2 + 1], t3);
lans = min(fp, *ST.lower_bound(t3));
cout << lans << '
';
}
}
}
return 0;
}