【BZOJ 3489】A Simple RMQ Problem
阿新 • • 發佈:2018-12-13
題目描述
詢問區間內只出現過一次的數最大值
Sol
直接做不好做 , 我們考慮一個數的可能的對詢問的影響
假設對於位置 上的數 , 它前一個和他相同的數的位置是 , 後一個和他相同的數的位置是(沒有則各自為 , ) 那麼顯然的 , 當詢問的範圍滿足 ,時 該數可能成為答案
這不就是個矩形覆蓋嗎? 於是來一發二維線段樹就可以了 查詢相當於是單點詢問
複雜度是
#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;
}