Luogu4137 Rmq Problem / mex(主席树,线段树上二分)(区间mex问题)
https://www.luogu.com.cn/problem/P4137?contestId=68990
- 若知道所有数字最后出现的位置,对于查询区间[l, r], num最后出现的位置pos小于l的话,则[l,r]一定不含num,pos大于r的话,就不知道了。
- 使用主席树,对于区间[l,r]查询rt[r],则可以避免pos大于r的情况
- 维护权值线段树,值是权值最后出现的位置。
- 样答案就可以在rt[r]根的树上二分,找位小于l的最小的数
- 注意主席树值域是题目值域+1
同样主席树维护数值最后出现位置的还有 区间种类数问题
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
//#define int long long
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1004535809;
const double PI = acos(-1.0);
int a[N], rt[N], sz;
struct Tree {
int val, lc, rc;
} tree[N * 40];
void modify( int pos, int val, int l, int r, int &now, int pre) {
now = ++ sz;
tree[now] = tree[pre];
if( l == r) {
tree[now].val = val; return;
}
int mid = l + r >> 1;
if(pos <= mid) modify( pos, val, l, mid, tree[now].lc, tree[pre].lc);
else modify( pos, val, mid + 1, r, tree[now].rc, tree[pre].rc);
tree[now].val = min(tree[tree[now].lc].val, tree[tree[now].rc].val);
}
int query( int val, int l, int r, int now ) {
if(l == r) {
return l;
}
int mid = l + r >> 1;
if(tree[tree[now].lc].val < val) return query ( val, l, mid, tree[now].lc);
else return query( val, mid + 1, r, tree[now].rc );
}
int main() {
IOS
int n, m; cin >> n >> m;
int limit = N - 5 + 1;
for ( int i = 1; i <= n; ++ i ) cin >> a[i], modify( a[i], i, 0, limit, rt[i], rt[i - 1]);
while( m -- ) {
int l, r; cin >> l >> r;
cout << query( l, 0, limit, rt[r]) << '\n';
}
return 0;
}