维护后面的position sg函数概念,离线+线段 bzoj 3339

时间:2022-02-12 00:55:41

3339: Rmq Problem

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1160  Solved: 596
[Submit][Status][Discuss]

Description

维护后面的position   sg函数概念,离线+线段   bzoj 3339

Input

维护后面的position   sg函数概念,离线+线段   bzoj 3339

Output

维护后面的position   sg函数概念,离线+线段   bzoj 3339

Sample Input

7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7

Sample Output

3
0
3
2
4

HINT

维护后面的position   sg函数概念,离线+线段   bzoj 3339

Source

http://www.lydsy.com/JudgeOnline/problem.php?id=3339

思路:

首先,我们预处理处[1,i]区间中的mex函数,即mex[i]为(1~i)中没有出现过的数字。

然后对于区间的移动,从[l,r]->[l+1,r],我们定义next[l]表示下一次a[l]出现的位置。然后我们发现,如果next[l] >= r,那么区间[l,r]和[l+1,r]的sg函数是不一样的,所以,我们对于[ l+1,next[l]-1 ]区间进行修改操作,对mex取min的就好了。然后这步操作是区间操作,我们用线段树来解决就行。

然后我们开始从左到右暴力一遍,并且通过线段树来维护,lazy一下即可。

这题最关键的部分就是在于询问部分!

因为询问的话是询问一个区间[l,r]的,但是我们只需要询问第r个位置的mex的值是多少就好了。(因为线段树更新以后的[l+1, next[l] - 1 ]会对区间最小造成干扰,所以我们只需要知道在L之前,有没有一个区间能更新到R即可,所以就只需要查询R这个点)

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = + ;
vector<pair<int, int> > ve[maxn];
int tree[maxn << ], lazy[maxn << ];
int n, q;
int a[maxn], mex[maxn];
bool vis[maxn];
int nxt[maxn], pos[maxn]; void build_tree(int l, int r, int o){
lazy[o] = -;
if (l == r){
tree[o] = mex[l]; return ;
}
int mid = (l + r) / ;
build_tree(l, mid, o << );
build_tree(mid + , r, o << | );
tree[o] = min(tree[o << ], tree[o << | ]);
} void push_down(int o){
int lb = o << , rb = o << | ;
if (lazy[lb] == - || lazy[lb] > lazy[o]){
lazy[lb] = lazy[o];
tree[lb] = min(tree[lb], lazy[lb]);
}
if (lazy[rb] == - || lazy[rb] > lazy[o]){
lazy[rb] = lazy[o];
tree[rb] = min(tree[rb], lazy[rb]);
}
tree[o] = -;
} int query(int x, int l, int r, int o){
if (x == l && x == r){
return tree[o];
}
if (lazy[o] != -) push_down(o);
int mid = (l + r) / ;
if (x <= mid) return query(x, l, mid, o << );
if (x > mid) return query(x, mid + , r, o << | );
} void update(int ql, int qr, int l, int r, int o, int val){
if (ql <= l && qr >= r){
if (lazy[o] == -) lazy[o] = val;
lazy[o] = min(lazy[o], val);
tree[o] = min(lazy[o], tree[o]);
return ;
}
if (lazy[o] != -)push_down(o);
int mid = (l + r) / ;
if (ql <= mid) update(ql, qr, l, mid, o << , val);
if (qr > mid) update(ql, qr, mid + , r, o << | , val);
tree[o] = min(tree[o << ], tree[o << | ]);
}
int ans[maxn];
void solve(){
build_tree(, n, );
for (int i = ; i <= n; i++){
for (int j = ; j < ve[i].size(); j++){
int pos = ve[i][j].fi, id = ve[i][j].se;
ans[id] = query(pos, , n, );
}
int lb = i + , rb = nxt[i] - ;
if (lb <= rb) update(lb, rb, , n, , a[i]);
}
for (int i = ; i <= q; i++){
printf("%d\n", ans[i]);
}
} int main(){
cin >> n >> q;
for (int i = ; i <= n; i++) {
scanf("%d", a + i);
vis[a[i]] = true;
mex[i] = mex[i - ];
while (vis[mex[i]]) mex[i]++;
pos[i] = n + ;
}
for (int i = ; i <= n; i++) pos[i] = n + ;
for (int i = n; i >= ; i--){
nxt[i] = pos[a[i]];
pos[a[i]] = i;
}
for (int i = ; i <= q; i++){
int l, r; scanf("%d%d", &l, &r);
ve[l].pb(mk(r, i));
}
solve();
return ;
}