首页 > 其他分享 >NOIP集训 P4137 Rmq Problem / mex 题解

NOIP集训 P4137 Rmq Problem / mex 题解

时间:2024-11-16 16:56:27浏览次数:1  
标签:rt Rmq NOIP int 题解 read le 值域 mex

前置指使:可持久化线段树

题解:P4137 Rmq Problem / mex

有一个长度为 \(n\) 的数组 \(\{ a_1,a_2,...,a_n \}\) 。
\(m\) 次询问,每次询问一个区间内最小没有出现过的自然数。

Input

第一行,两个正整数 \(n,m\) 。
第二行,\(n\) 个非负整数 \(a_1, a_2,...,a_n\) 。
接下来 \(m\) 行,每行两个正整数 \(l,r\),表示一次询问。

Output

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

Note

对于 \(100\%\) 的数据:\(1\le n,m\le 2e5, 1\le l\le r\le n,0\le a_i\le 2e5\)。

分析

思考 \(mex\) 的本质。对于一段给定的区间,\(mex\) 即是从 \(0\) 开始存在的连续值域的最大值加 \(1\)。若 \(0\) 不在区间值域中则 \(mex\) 为 \(0\)。
在值域线段树上考虑问题。序列中的值暂时不用考虑,因为可以二分值域直接处理。对于 \([l,r]\) 的 \(mex\) ,即是要找到一个最小的 \(i\) ,使得这个 \(i\) 最后出现的位置 \(last_i\) 小于 \(l\)。
所以可以在主席树上维护每个值出现位置的 \(min\),注意加入时要把 \(x\) 加上 \(1\) ,再在查询时减去 \(1\) 防止值域出现问题.
数据不需要离散化。同时,对于大于 \(n\) 的 \(a_i\) 显然对答案没有任何贡献,因为这时必然存在一个小于等于 \(n\) 的 \(mex\)。

AC代码:

#include<bits/stdc++.h>
using namespace std;

inline int read() {
	int f = 1, otto = 0;
	char a = getchar();
	while(!isdigit(a)) {
		if(a == '-') f = -1;
		a = getchar();
	}
	while(isdigit(a)) {
		otto = (otto << 1) + (otto << 3) + (a ^ 48);
		a = getchar();
	}
	return f * otto;
}

const int maxn = 2e5 + 10;
int ver;
int rt[maxn], tr[maxn << 5], ls[maxn << 5], rs[maxn << 5];

void upd(int &u1, int u2, int l, int r, int num, int loc) {
	if(!u1) u1 = ++ver;
	if(l == r) return tr[u1] = loc, void(0);
	
	int mid = l + r >> 1;
	if(num <= mid) rs[u1] = rs[u2], upd(ls[u1], ls[u2], l, mid, num, loc);
	else ls[u1] = ls[u2], upd(rs[u1], rs[u2], mid + 1, r, num, loc);
	
	return tr[u1] = min(tr[ls[u1]], tr[rs[u1]]), void(0);
} 

int ask(int u, int l, int r, int lim) {
	if(l == r) return l;
	
	int mid = l + r >> 1;
	if(tr[ls[u]] < lim) return ask(ls[u], l, mid, lim);
	else return ask(rs[u], mid + 1, r, lim); 
}

int main() {
	int n = read() + 1, m = read();
	for(int i = 1; i < n; i++) {
		int x = read() + 1;
		if(x > n) rt[i] = rt[i - 1];
		else upd(rt[i], rt[i - 1], 1, n, x, i);
	}
	while(m--) {
		int l = read(), r = read();
		printf("%d\n", ask(rt[r], 1, n, l) - 1);
	}
	return 0;
}

小结:

对于类似的题套路性很强,但是转化具有一定的思维难度。要多做题,多见题才更能掌握主席树的应用。

标签:rt,Rmq,NOIP,int,题解,read,le,值域,mex
From: https://www.cnblogs.com/Ydoc770/p/18547716

相关文章

  • 蓝桥杯模拟赛(第一期)个人题解&感想
    林专大一牲第一次写blog,更新较慢,写的不好的地方请见谅(好多题目忘记了题号and暂时没有题目要求的内容…后面会补充的!)本次带来的是蓝桥杯模拟赛第一期的个人题解(笨人水平较低,大家可以在评论区指出错误/讨论更优解~)大多题我是用c++写的,但也掺了几道c,为以后全面用c++打比赛作过......
  • AI|经常崩溃的问题解决
    AdobeIllustratorCrashes网络上大部分说法都是重装AI,兼容性问题,管理员权限或者是版本不对,经测试均无效,甚至出现重装系统这种离谱的办法,正确的解决办法是把首选项的性能里的GPU取消勾选,或者再把电脑的虚拟内存扩大即可。 Step1:打开首选项 Step2:取消勾选GPU性能......
  • CF987 Div2 F 题解
    阶段1考虑我们每次随机删除两个然后询问,若中位数为\(\frac{n}{2},\frac{n}{2}+1\)称被删除的两个为基准数,用\(v_1,v_2\)代表。每次询问得到解的概率约为\(\frac{1}{2}\)。发现基准数一定一个\(<\frac{n}{2}\)一个\(>\frac{n}{2}+1\),且对于一次四个数的询问\(x......
  • [AGC018C] Coins 题解
    先全部选\(a_i\),假设\(b_i=b_i-a_i,c_i=c_i-a_i\)。那么题目转化为选\(y\)个\(b\)和\(z\)个\(c\)使得答案最大。会发现若\(i\)位置选的\(b\),\(j\)位置选的\(c\),那么需要满足\(b_i-c_i>b_j-c_j\)。我们按上述条件排序,这样一定是在左边选\(b\),右边选\(c\)。那......
  • CSP/信奥赛C++语法基础刷题训练(9):洛谷P1035:[NOIP2002 普及组] 级数求和
    CSP/信奥赛C++语法基础刷题训练(9):洛谷P1035:[NOIP2002普及组]级数求和题目描述已知:Sn=1......
  • CSP/信奥赛C++语法基础刷题训练(10):洛谷P1307:[NOIP2011 普及组] 数字反转
    CSP/信奥赛C++语法基础刷题训练(10):洛谷P1307:[NOIP2011普及组]数字反转题目描述给定一个整数NNN,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,......
  • [DMY]2024 NOIP 模拟赛 Day 9
    比赛7:30开始,我8:10到的机房。赛时T1看了一眼后以为是双指针,然后开始写,写到一半发现假飞了。想了一会发现除了随机化以外没有任何思路,所以写个\(n^2\)暴力就扔了。去看T2,像是个DP题。先把组合数复杂度的暴力写了,发现不太好写。我用了\(n\)遍dikstra,但其实用Floyd......
  • 炼石计划 NOIP 模拟赛 #20
    A.\(kx+(\sum_{i=1}^{k}a_i-1)\timesy=k(x-y)+y\times\sum_{i=1}^{k}a_i\)\((a_1-1)*1+(a_2-1)*(a_1-1)*1+(a_3-1)*(a_2-1)*(a_1-1)*1\)$\prod_{i=1}^{k}a_i>N$两数和相等时乘积最大,因此\(a\)数组中任意两个数的差的绝对值......
  • 题解:ABC013D 阿弥陀
    先考虑\(D=1\),明显可以\(O(M)\)模拟预处理出在最上面的每个位置往下走会走到什么位置,之后每次就可以\(O(1)\)查询了。当\(D>1\)时,可以依赖预处理的数据每次\(O(D)\)暴力查询。又注意到每次对所有位置进行的变换操作是一样的,可以倍增后用类似快速幂的方法优化到\(O(\log......
  • CF2031D 题解
    原题链接最后悔的一集,感觉D\(<\)everything。考虑由确定的点推出其他点的答案,发现最高点的答案是确定的,设其位置为\(x\)。然后根据题目定义,发现可以分成\([1,x-1],[x,n]\)两个区间,\([x,n]\)答案均为\(h_x\)。对于\([1,x-1]\)区间,我们找到第一个\(>[x,n]\)区间最小......