题目链接
询问区间内只出现过一次的数最大值
直接做不好做 , 我们考虑一个数的可能的对询问的影响
假设对于位置 i i i 上的数 , 它前一个和他相同的数的位置是 p r e i pre_i prei , 后一个和他相同的数的位置是 n x t i nxt_i nxti(没有则各自为 0 0 0 , n + 1 n+1 n+1)
那么显然的 , 当询问的范围满足 L ∈ [ p r e i + 1 , i ] L \in [pre_i+1,i] L∈[prei+1,i] , R ∈ [ i , n x t i − 1 ] R \in [i,nxt_i-1] R∈[i,nxti−1]时
该数可能成为答案
这不就是个矩形覆盖吗?
于是来一发二维线段树就可以了
查询相当于是单点询问
复杂度是 O ( ( n + Q ) l o g 2 n ) O((n+Q)log^2n) O((n+Q)log2n)
#include
#include
#include
#include
#include
#include
#include
#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;
}