2018.10.31 bzoj3339&&3585mex(主席樹)
阿新 • • 發佈:2018-12-18
傳送門 雙倍經驗 直接上主席樹,每個葉節點維護這個值出現的最右區間,非葉子節點維護當前值域內所有最右區間的最小值。 查詢的時候只用在以為根的樹上面二分。 看左兒子滿沒有就只用看左邊的最小值是不是大於就行了。 程式碼:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<< 3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=2e5+5;
int n,q,rt[N],mex[N*50],son[N*50][2],tot=0,sig=0;
inline void update(int&p,int las,int l,int r,int k,int v){
p=++tot,son[p][0]=son[las][0],son[p][1]=son[las][1],mex[p]=mex[las];
if(l==r){mex[p]=v;return;}
int mid=l+r>>1 ;
if(k<=mid)update(son[p][0],son[las][0],l,mid,k,v);
else update(son[p][1],son[las][1],mid+1,r,k,v);
mex[p]=min(mex[son[p][0]],mex[son[p][1]]);
}
inline int query(int p,int l,int r,int k){
if(l==r)return l;
int mid=l+r>>1;
if(mex[son[p][0]]>=k)return query(son[p][1],mid+1,r,k);
return query(son[p][0],l,mid,k);
}
int main(){
n=read(),q=read();
for(int i=1;i<=n;++i)update(rt[i],rt[i-1],0,1e9,read(),i);
for(int i=1,l,r;i<=q;++i)l=read(),r=read(),printf("%d\n",query(rt[r],0,1e9,l));
return 0;
}