1. 程式人生 > >【BZOJ 3489】A Simple RMQ Problem

【BZOJ 3489】A Simple RMQ Problem

題目連結

題目描述

詢問區間內只出現過一次的數最大值

Sol

直接做不好做 , 我們考慮一個數的可能的對詢問的影響

假設對於位置 ii 上的數 , 它前一個和他相同的數的位置是 preipre_i , 後一個和他相同的數的位置是nxtinxt_i(沒有則各自為 00 , n+1n+1) 那麼顯然的 , 當詢問的範圍滿足 L[prei+1i]L \in [pre_i+1,i]R[inxti1]R \in [i,nxt_i-1]時 該數可能成為答案

這不就是個矩形覆蓋嗎? 於是來一發二維線段樹就可以了 查詢相當於是單點詢問

複雜度是O((n+Q)log2n)O((n+Q)log^2n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#define Set(a,b) memset(a,b,sizeof(a))
#define read(a) scanf("%d",&a)
#define readl(a) scanf("%lld",&a)
using namespace std; int n,m; const int N=1e5+10; const int MAXN=2e7; const int OO=4e5; struct segment_tree{ int ls,rs;int Max,tag; segment_tree(){ls=rs=Max=tag=0;} }T[MAXN];int cur; struct node{int ls,rs,sub,Max;node(){ls=rs=Max=0;}}tr[OO]; int rt;int cnt=0; int lst[N],a[N],L[N],R[N]; inline void Supdate
(int u) {T[u].Max=max(T[u].Max,max(T[T[u].ls].Max,T[T[u].rs].Max));}//標記永久化了 , 不能只用左右兒子轉移 void Smodify(int &u,int l,int r,int L,int R,int x){ if(!u) u=++cur; if(l>=L&&r<=R) {T[u].Max=max(T[u].Max,x);T[u].tag=max(T[u].tag,x);return;} int mid=l+r>>1; if(mid>=R) Smodify(T[u].ls,l,mid,L,R,x); else if(mid<L) Smodify(T[u].rs,mid+1,r,L,R,x); else Smodify(T[u].ls,l,mid,L,mid,x),Smodify(T[u].rs,mid+1,r,mid+1,R,x); return Supdate(u); } int ans; inline void update(int u){tr[u].Max=max(tr[u].Max,max(tr[tr[u].ls].Max,tr[tr[u].rs].Max));} void Modify(int &u,int l,int r,int L,int R,int LL,int RR,int x) { if(!u) u=++cnt; if(l>=L&&r<=R) {Smodify(tr[u].sub,1,n,LL,RR,x);tr[u].Max=max(tr[u].Max,T[tr[u].sub].Max);return;} int mid=l+r>>1; if(mid>=R) Modify(tr[u].ls,l,mid,L,R,LL,RR,x); else if(mid<L) Modify(tr[u].rs,mid+1,r,L,R,LL,RR,x); else Modify(tr[u].ls,l,mid,L,mid,LL,RR,x),Modify(tr[u].rs,mid+1,r,mid+1,R,LL,RR,x); return update(u); } void SQuery(int u,int l,int r,int Y) { if(!u) return; ans=max(ans,T[u].tag); if(ans>=T[u].Max) return; if(l==r) return; int mid=l+r>>1; if(mid>=Y) return SQuery(T[u].ls,l,mid,Y); else return SQuery(T[u].rs,mid+1,r,Y); return; } void Query(int u,int l,int r,int X,int Y) { if(!u) return; if(ans>=tr[u].Max) return; SQuery(tr[u].sub,1,n,Y);//標記永久化後每個點都要詢問一次 , 因為是單點詢問 , 可以保證複雜度 if(l==r) return; int mid=l+r>>1; if(mid>=X) Query(tr[u].ls,l,mid,X,Y); else Query(tr[u].rs,mid+1,r,X,Y); return; } int main() { read(n);read(m); for(int i=1;i<=n;++i){ read(a[i]);L[i]=lst[a[i]]+1; lst[a[i]]=i; } for(int i=1;i<=n;++i) lst[i]=n+1; for(int i=n;i;--i){R[i]=lst[a[i]]-1;lst[a[i]]=i;} for(int i=1;i<=n;++i) Modify(rt,1,n,L[i],i,i,R[i],a[i]); int lastans=0,x,y,l,r; while(m--){ read(x);read(y); l=(x+lastans)%n+1; r=(y+lastans)%n+1; if(l>r) swap(l,r); ans=0;Query(rt,1,n,l,r); printf("%d\n",ans); lastans=ans; } return 0; }