[BZOJ3585][BZOJ3339]mex

试题描述

有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

输入

第一行n,m。
第二行为n个数。
从第三行开始,每行一个询问l,r。

输出

一行一个数,表示每个询问的答案。

输入示例

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

输出示例

1
2
3
0
3

数据规模及约定

对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n

题解

首先离线,将询问按右端点排序。然后我们就可以从左到右一个个添加序列中的数了。现在我们可以认为右端点固定为 R 了,考虑一个数 i,我们只关心左边离它最近的位置,不妨称为 lstp[i],那么 mex{ A[L..R] } = k 等价于 min{ lstp[0..k-1] } ≥ L,即小于 k 的数上一次出现的位置在 L 及之后,即 [L, R] 中包含了所有 0 到 k-1 中的数字。这样,我们维护一个权值线段树,支持点修改,在查询时可以直接在线段树上二分。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
	return x * f;
}

#define maxn 200010
#define maxnode 6000010
#define maxv 1000000000

int n, q, A[maxn], num[maxn];

struct Que {
	int l, r, id;
	Que() {}
	Que(int _1, int _2, int _3): l(_1), r(_2), id(_3) {}
	bool operator < (const Que& t) const { return r < t.r; }
} qs[maxn];

int ToT, mnv[maxnode], lc[maxnode], rc[maxnode], rt;
void update(int& o, int l, int r, int val, int npos) {
	if(!o) o = ++ToT;
	if(l == r) mnv[o] = npos;
	else {
		int mid = l + r >> 1;
		if(val <= mid) update(lc[o], l, mid, val, npos);
		else update(rc[o], mid + 1, r, val, npos);
		mnv[o] = min(mnv[lc[o]], mnv[rc[o]]);
	}
	return ;
}
int query(int lim) {
	int l = 0, r = maxv, o = rt;
	while(l < r) {
		if(!o) return l;
		int mid = l + r >> 1;
		if((lc[o] ? mnv[lc[o]] : 0) >= lim) l = mid + 1, o = rc[o];
		else r = mid, o = lc[o];
	}
	return l;
}

int Ans[maxn];

int main() {
	n = read(); q = read();
	for(int i = 1; i <= n; i++) A[i] = read();
	for(int i = 1; i <= q; i++) {
		int l = read(), r = read();
		qs[i] = Que(l, r, i);
	}

	sort(num + 1, num + n + 1);
	sort(qs + 1, qs + q + 1);
	for(int i = 1, j = 1; i <= q; i++) {
		while(j <= qs[i].r) update(rt, 0, maxv, A[j], j), j++;
		Ans[qs[i].id] = query(qs[i].l);
	}

	for(int i = 1; i <= q; i++) printf("%d\n", Ans[i]);

	return 0;
}
时间: 2024-08-07 16:46:24

[BZOJ3585][BZOJ3339]mex的相关文章

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

BZOJ3339:Rmq Problem &amp; BZOJ3585 &amp; 洛谷4137:mex——题解

前者:https://www.lydsy.com/JudgeOnline/problem.php?id=3339 后者: https://www.lydsy.com/JudgeOnline/problem.php?id=3585 https://www.luogu.org/problemnew/show/P4137 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 题解大部分都是莫队分块,但是复杂度为O(n*sqrt(n))=5e2*2e5=1e

bzoj3585 mex

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3585 [题解] 哎好像就是上题啊 怎么权值是1e9了啊 那没关系啊把主席树调成[0,1e9]的就行啦 哎调调空间 过了 # include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; type

bzoj3339 rmq problem (range mex query)

给一个长度为n的数列a,q个询问,每次询问一段区间的mex.(没有出现过的最小非负整数) 1<=n,q<=200000,0<=ai<=200000. 题解1 莫队 我们将权值分成根号块,记录每个权值的出现次数和每块内有多少权值出现过. 修改和询问就直接暴力做就行. 修改O(1),询问O(sqrt(n)),加在一起还是O((n+q)sqrt(n+q)). #include <iostream> #include <stdio.h> #include <s

【莫队算法】【权值分块】bzoj3585 mex

orz PoPoQQQ. 本来蒟蒻以为这种离散化以后就对应不起来的题不能权值分块搞的说. ……结果,实际上>n的权值不会对答案作出贡献. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 200002 #define BN 452 int n,m,num[N],a[N],l[BN],size[BN],anss[N],b[N],sumv[BN]; s

【bzoj3339】Rmq Problem

[bzoj3339]Rmq Problem Description Input Output Sample Input 7 50 2 1 0 1 3 21 32 31 43 62 7 Sample Output 30324 HINT 分析 离线算法. 对于[l,r]区间的询问,我们可以线性求出来,然后考虑[l+1,r]区间有什么不同,在a[l]下一次出现的位置之前,所有大于a[l]的mex,都变成是a[l],因为 [l+1,a[l]下一次出现的位置-1],这个区间内没有a[l]了,大于它的数当然

matlab-bgl 工具包配置环境 TDM-GCC-64 mex

Windows 64 + Matlab 64 MEX混合编程初步: http://blog.csdn.net/enjoyyl/article/details/46545263 使用的是 TDM-GCCgccg For Matlab 2015 TDM-GCC-64 来自 51CTO下载-tdm64-gcc-4.9.2-3.zip matlab-bgl工具包下载: http://www.pudn.com/downloads737/sourcecode/math/detail2943220.html

HDU #4747 MEX

题目描述: 定义 mex(i, j) 为序列中第 i 项到第 j 项中没有出现的最小自然数.给定序列,求 Σ1≤i,j≤n,i≤j mex(i, j). 解题思路: 首先我们可以 O(n) 预处理出 mex(1, 1 ~ n),因为显然的是mex是递增的.然后我们考虑怎么从 mex(i, i ~ n) 推出 mex(i + 1, i + 1 ~ n),我们删掉 a[i] 这个数后,哪些区间的mex会改变呢?其实就是到下一个a[i]出现前mex大于a[i]的区间,因为这段区间没有了a[i]这个数,

在Visual Studio中开发Matlab mex文件,生成mexw64/mexw32

csunking贡献,2015-9-22 1712 1.   概述 通过使用C/C++与Matlab混合编程,既可以享受到C代码快速执行的速度,又可以方便的使用Matlab众多的库函数和强大的绘图功能.让Matlab调用C函数是通过DLL文件实现的,而这个DLL的开发过程不仅仅可以使用Matlab自带的mex命令,还可以使用VC++开发环境,使用VC有很多好处,一是让我回到了原来熟悉的开发环境中,二能够使用更加标准的C++编译器,第三点也是最爽的,可以使用VC强大的调试功能. 此次文档更新时使用