1. 程式人生 > >2018.10.31 bzoj3339&&3585mex(主席樹)

2018.10.31 bzoj3339&&3585mex(主席樹)

傳送門 雙倍經驗 直接上主席樹,每個葉節點維護這個值出現的最右區間,非葉子節點維護當前值域內所有最右區間的最小值。 查詢的時候只用在以root[qr]root[qr]為根的樹上面二分。 看左兒子滿沒有就只用看左邊的最小值是不是大於qlql就行了。 程式碼:

#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; }