题意:
给你一个长度为
n
n
n的序列,然后
m
m
m个询问,你有两种操作,定义如下:
1.
1
x
y
1.\ 1\ x\ y
1. 1 x y,即令
a
x
=
y
a_x = y
ax=y,修改操作.
2.
2
l
r
2.\ 2 \ l \ r
2. 2 l r,表示询问你区间
[
l
,
r
]
[l,r]
[l,r]内所有的数的
M
e
x
Mex
Mex是多少,即这
r
−
l
+
1
r - l + 1
r−l+1个数所不能组成的最小的正整数是多少?
思路:
哇昆明出题人不讲武德,也是自己的锅,当时很久之前是训练过2019徐州的,但是还是没有看到这个题,昆明
M
M
M就是这个题的简化版,少了一个
l
o
g
log
log,无动态的要求。
那就思路操作就很明显了,就和昆明的
M
M
M题一样的操作,具体操作思路和复杂度证明 移步另一篇博客,然后这个题就是在那个题的基础上加上了动态主席树罢了,剩下的操作完全相同。
当做套路题好好掌握起来啊。
emmmm不开LL 会超时滴,写结构体也会超时滴,不知道为何,是常数太大嘛,但也不应该qwq,以后还是写数组的吧
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e5 + 10;
int n,m,cnt,a[N];
ll tree[N * 150];
int ls[N * 150],rs[N * 150],root[N],tot;
int totx,toty,x[N],y[N];
//这尼玛就离谱 昆明整个2019徐州原题 还不用带修 艹 我为什么不早补
void modify(int &now,int pre,int l,int r,int p,int v) {
if(!now) now = ++tot;
tree[now] = tree[pre],ls[now] = ls[pre],rs[now] = rs[pre];
if(l == r) {
tree[now] += v; return ;
}
int mid = (l + r) >> 1;
if(p <= mid) modify(ls[now],ls[pre],l,mid,p,v);
else modify(rs[now],rs[pre],mid+1,r,p,v);
tree[now] = tree[ls[now]] + tree[rs[now]];
}
ll query(int l,int r,int R) {
if(r <= R) {
ll ss = 0;
for(int i = 1;i <= totx;i ++) ss -= tree[x[i]];
for(int i = 1;i <= toty;i ++) ss += tree[y[i]];
return ss;
}
int mid = (l + r) >> 1;
if(R <= mid) {
for(int i = 1;i <= totx;i ++) x[i] = ls[x[i]];
for(int i = 1;i <= toty;i ++) y[i] = ls[y[i]];
return query(l,mid,R);
}
else {//不开多个数组记录一下的话 要保证走完这一层不会再返回来了
ll ss = 0;
for(int i = 1;i <= totx;i ++) ss -= tree[ls[x[i]]];
for(int i = 1;i <= toty;i ++) ss += tree[ls[y[i]]];
for(int i = 1;i <= totx;i ++) x[i] = rs[x[i]];
for(int i = 1;i <= toty;i ++) y[i] = rs[y[i]];
return ss + query(mid+1,r,R);
}
}
inline int lowbit(int x) { return x & (-x); }
void add(int pos,int vpos,int v) {//pos 对应区间即bit修改的位置 vpos对应值域即主席树修改的位置
for(int i = pos;i <= n;i += lowbit(i)) {
modify(root[i],root[i],1,200000,vpos,v);
}
}
void work(int l,int r) {
totx = 0,toty = 0;
for(int i = l - 1;i;i -= lowbit(i)) x[++totx] = root[i];
for(int i = r;i;i -= lowbit(i)) y[++toty] = root[i];
}
int main() {
scanf("%d%d",&n,&m);
// build(root[0],1,200000);
for(int i = 1;i <= n;i ++) {
scanf("%d",&a[i]);
add(i,a[i],a[i]);
}
int op,l,r,x,y;
for(int i = 1;i <= m;i ++) {
scanf("%d",&op);
if(op == 1) {
scanf("%d%d",&x,&y);
add(x,a[x],-a[x]);
add(x,y,y);
a[x] = y;
}
else {
scanf("%d%d",&l,&r);
ll now = 1,sum = 0;
while(true) {
work(l,r);
int MAX = min(1LL * 200000,now);
// cout << "f + 1 = "<< MAX << '\n';
ll tmp = query(1,200000,MAX);
// cout << "ans = " << ff << '\n';
if(tmp == sum) {
printf("%lld\n",now); break;
}
// f = ff;
sum = tmp; now = sum + 1;
}
// printf("%lld\n",f + 1);
}
}
return 0;
}