洛谷 P4137 Rmq Problem mex 莫队 + 值域分块

Rmq Problem / mex

题目描述#

有一个长度为 n 的数组 {a1,a2,,an}

m 次询问,每次询问一个区间内最小没有出现过的自然数。

输入格式#

第一行,两个正整数 n,m
第二行,n 个非负整数 a1,a2,,an
接下来 m 行,每行两个正整数 l,r,表示一次询问。

输出格式#

输出 m 行,每行一个数,依次表示每个询问的答案。

样例 #1#

样例输入 #1#

5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5

样例输出 #1#

1
2
3
0
3

提示#

对于 30% 的数据:1n,m1000
对于 100% 的数据:1n,m2×1051lrn0ai2×105


SOLUTION#

对值域进行分块,当每个块里面存在的数字为块长的时候,mex 一定不在这个区间内,因此查询答案的时候可以暴力枚举每个块,每次查询复杂度为 O(n)adddel 操作的复杂度均为 O(1),总体复杂度为 O(nn)

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
// #define int __int128
namespace io {
  constexpr int BUFFER_SIZE = 1 << 16;
  char buffer[BUFFER_SIZE], *head, *tail;

  char get_char() {
    if (head == tail) {
      int l = (int) fread(buffer, 1, BUFFER_SIZE, stdin);
      tail = (head = buffer) + l;
    }
    return *head++;
  }

  int read() {
    int x = 0, f = 1;
    char c = get_char();
    for (; !isdigit(c); c = get_char())
      if (c == '-') f = -1;
    for (; isdigit(c); c = get_char()) x = x * 10 + c - '0';
    return x * f;
  }

  void print(int x) {
    static int sta[1997];
    int top = 0;
    do {
      sta[top++] = x % 10, x /= 10;
    } while (x);
    while (top) putchar(sta[--top] + 48);  // 48 是 '0'
  }

  void println(int x) { print(x), putchar('\n'); }
}  // namespace io
using namespace io;

const int N = 2e5 + 10, M = 510;

int n, m, block;
int belong[N], cnt[N], a[N], ans[N], tot[N], bl[N], br[N];

struct node {
	int l, r, id;
	bool operator < (const node &T) const {
    return belong[l] ^ belong[T.l] ? belong[l] < belong[T.l] : ((belong[l] & 1) ? r < T.r : r > T.r);
	}
} modui[N];

void add(int x) {
  if (!cnt[x]) tot[belong[x]] ++;
  cnt[x] ++;
}

void del(int x) {
  if (cnt[x] == 1) tot[belong[x]] --;
  cnt[x] --; 
}

int query() {
  int now = 0;
  while (tot[now] == br[now] - bl[now] + 1) ++ now;
  for (int i = bl[now]; i <= br[now]; i ++ ) {
    if (!cnt[i]) return i;
  }
  return -1;
}

int main() {
	n = read(); m = read(); block = sqrt(n); // 0, ...
  belong[0] = 0;
	for(int i = 1; i <= n; i ++ ) { a[i] = min(read(), n + 1); belong[i] = i / block; } 
  belong[n + 1] = (n + 1) / block; belong[n + 2] = (n + 2) / block;
	for(int i = 1; i <= m; i ++ ) {
    modui[i].l = read(), modui[i].r = read(); modui[i].id = i;
	}	

  for (int i = 0; i <= belong[n + 1]; i ++ ) {
    bl[i] = i * block;
    br[i] = bl[i] + block - 1;
  }
	  
	sort(modui + 1, modui + 1 + m);
	int lal = modui[1].l, lar = modui[1].l - 1;
	for(int i = 1; i <= m; i ++ ) {
		int l = modui[i].l, r = modui[i].r;
		while(lal > l) lal --, add(a[lal]);
		while(lar < r) lar ++, add(a[lar]);
		while(lal < l) del(a[lal]), lal ++;
		while(lar > r) del(a[lar]), lar --;
		ans[modui[i].id] = query();
	}
	for(int i = 1; i <= m; i ++ ) {
    println(ans[i]);
	}
	
  return 0;
}
posted @   ccz9729  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
主题色彩