luogu P4137 mex
题面:
有一个长度为$n$的数组${a1,a2,…,an}$。$m$次询问,每次询问一个区间内最小没有出现过的自然数。
令$lst[i][r]$表示在$[1, r]$中数值$i$最后出现的位置
那么,我们要求的便是$min(t)$
使得$lst[t][r] \geqslant l(0 \leqslant t \leqslant t - 1)$
注意到$lst[][i]$相比于$lst[][i - 1]$其实只有一个地方变化了
可以考虑用可持久化线段树
$t$可以选择在线段树上二分,相应地需要维护$lst[]$的最小值
都挺简单,相信你们都会打代码吧
果然有不是差分的题。。。。。
#include <cstdio> #include <algorithm> #include <iostream> #define sid 10000050 #define ri register int using namespace std; char RR[23345]; extern inline char gc() { static char *S = RR + 22000, *T = RR + 22000; if(S == T) fread(RR, 1, 22000, stdin), S = RR; return *S ++; } inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') { p = p * 10 + c - '0'; c = gc(); } return p * w; } int n, m, cnt, tot; int rt[200050], ls[sid], rs[sid], minhp[sid]; void Insert(int &now, int pre, int l, int r, int val, int pos) { now = ++ cnt; ls[now] = ls[pre]; rs[now] = rs[pre]; if(l == r) { minhp[now] = pos; return; } int mid = (l + r) >> 1; if(val <= mid) Insert(ls[now], ls[pre], l, mid, val, pos); else Insert(rs[now], rs[pre], mid + 1, r, val, pos); minhp[now] = min(minhp[ls[now]], minhp[rs[now]]); } int Query(int R, int l, int r, int L) { if(l == r) return l; int mid = (l + r) >> 1; if(minhp[ls[R]] < L) return Query(ls[R], l, mid, L); else return Query(rs[R], mid + 1, r, L); } int main() { n = read(); m = read(); for(ri i = 1; i <= n; i ++) { int u = read(); if(u >= n) rt[i] = rt[i - 1]; else Insert(rt[i], rt[i - 1], 0, n, u, i); } for(ri i = 1; i <= m; i ++) { int l, r; l = read(); r = read(); printf("%d\n", Query(rt[r], 0, n, l)); } return 0; }
喵喵喵?喵喵喵! 喵喵喵......