Rmq Problem / mex(BZOJ3585)

莫队+值域分块

莫队有\(O(n\sqrt{n})\)次修改,\(O(m)\)次查询,就不能用\(O(logn)\)修改与查询的线段树。而是用\(O(1)\)修改,\(O(\sqrt{n})\)查询的值域分块。同时\(a_i>n\)的数可以忽略。

复杂度\(O((n+m)\sqrt{n})\)

#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline int read() {
	int s = 0,w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-')
			w = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * w;
}
int n,m,block,tmp[N],a[N],c[N],bl[N],ans[N];
struct node {
	int l,r,v;
  	bool operator < (const node &x) const {
    	return bl[l] == bl[x.l] ? r > x.r : l < x.l;
  	}
}t[N];
void add(int x) {
  	if(x <= n) tmp[bl[x]] += !c[x]++;
}
void del(int x) {
  	if(x <= n) tmp[bl[x]] -= !--c[x];
}
void init(){
	n = read(),m = read(); 
  	block = sqrt(n);
  	for(int i = 1;i <= n;i++) a[i] = read(),bl[i] = (i - 1) / block + 1;
  	for(int i = 1;i <= m;i++) t[i].v = i,t[i].l = read(), t[i].r = read();
  	sort(t + 1,t + m + 1);
  	return ;
}
void solve(){
	int l = 1,r = 0;
  	for(int i = 1; i <= m; i++) {
    	while(l > t[i].l) add(a[--l]);
    	while(r < t[i].r) add(a[++r]);
    	while(l < t[i].l) del(a[l++]);
    	while(r > t[i].r) del(a[r--]);
    	if(!c[0]) continue;
    	int res = 1;
    	while(tmp[res] == block) res++;
    	res = (res - 1) * block + 1;
    	while(c[res]) res++;
    	ans[t[i].v] = res;
  	}
  	for(int i = 1;i <= m;i++) printf("%d\n", ans[i]);
	return ;
}
int main() {
	init();
  	solve();
  	return 0;
}
posted @ 2020-03-03 20:33  优秀的渣渣禹  阅读(109)  评论(0编辑  收藏  举报