P4137 Rmq Problem / mex 题解
前言
好久没用整体二分发电了。
正文
注意到实际上 mex 是可以二分的。
对于全局 mex 我们可以二分 mex 是哪个值。
check 为是否区间内比
这是显然正确的吧。
那么对于区间查询 mex,只需要更改 check,改为满足该条件下的 dp 的
条件:
-
a_i < a_j -
L \leqslant i \leqslant R -
L \leqslant j \leqslant R -
a_j \leqslant x
其中
注意到可以使用类似于扫描线的方法,询问和插入均按照右端点或下标从小到大排序,之后用整体二分二分
可能会有一些细节但不多。
代码
#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-x))
#define N 1000005
using namespace std ;
int n , q , tr[N] , last[N] , ans[N] , cnt=0 , num=0 ;
void change(int x,int k) {
while(x<=n+1) {
tr[x] += k ;
x += lowbit(x) ;
}
}
int ask(int x) {
int ans=0 ;
while(x) {
ans += tr[x] ;
x -= lowbit(x) ;
}
return ans ;
}
struct node {
int x , i , l , r , opt , k , tm ;
bool operator <(const node &a)const {
return this->tm>a.tm ;
}
} a[N],q1[N],q2[N];
void solve(int l,int r,int L,int R) {
if(l>r||L>R) return ;
int mid=(l+r)>>1 , tot1=0 , tot2=0 ;
for(int i=L; i<=R; i++) {
if(a[i].opt==1) {
if(a[i].x<=mid){
if(last[a[i].x]) change(last[a[i].x],-1) ;
last[a[i].x] = a[i].i ;
change(a[i].i,1) ;
q1[++tot1] = a[i] ;
} else q2[++tot2] = a[i] ;
} else {
int x=ask(a[i].r)-ask(a[i].l-1) ;
if(a[i].k+x<=mid) q1[++tot1] = a[i] ;
else if(x+a[i].k==mid+1) {
ans[a[i].i] = mid+1 ;
a[i].k += x ;
q2[++tot2] = a[i] ;
} else exit(114514) ;
}
}
for(int i=1; i<=tot1; i++) {
a[i+L-1] = q1[i] ;
if(q1[i].opt==1) {
if(last[q1[i].x]) {
change(last[q1[i].x],-1) ;
last[q1[i].x] = 0 ;
}
}
}
for(int i=1; i<=tot2; i++) a[i+L-1+tot1] = q2[i] ;
if(l!=r) solve(l,mid,L,L+tot1-1) ;
solve(mid+1,r,L+tot1,R) ;
}
int read() {
int x=0 ;
char a=getchar() ;
while(!(a>='0'&&a<='9')) a = getchar() ;
while(a>='0'&&a<='9') {
x *= 10 ;
x += a-'0' ;
a = getchar() ;
}
return x ;
}
bool cmp(node a,node b) {
return a.r==b.r?a.tm<b.tm:a.r<b.r ;
}
int t[N] ;
signed main(){
n = read() , q = read() ;
for(int i=1; i<=n; i++) {
int temp=read() ;
cnt++ ;
a[cnt].opt = 1 , a[cnt].k = 1 , a[cnt].x = temp , a[cnt].r = a[cnt].i = i , a[cnt].tm = cnt ;
}
for(int i=1; i<=q; i++) {
int x , y ;
x = read() , y = read() ;
cnt++ ;
a[cnt].i = ++num , a[cnt].opt = 2 , a[cnt].l = x , a[cnt].r = y , a[cnt].tm=cnt ;
}
sort(a+1,a+1+cnt,cmp) ;
solve(0,n+1,1,cnt) ;
for(int i=1; i<=num; i++) printf("%d\n",ans[i]) ;
return 0 ;
}
废话
本人模拟赛做该题的待修版(单点),把 check 推成了等于 高级错误(实际上还有 multiset 用 end 查最大值这种发电操作)。