BZOJ3489:A simple rmq problem
浅谈主席树:https://www.cnblogs.com/AKMer/p/9956734.html
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3489
题目意思就是在线求\(pos\)在\([l,r]\),\(lst\)在\([0,l-1]\),\(nxt\)在\([r+1,n+1]\)的点中权值最大的。其中\(pos\)表示这个点的下标,\(lst\)表示上一个跟这个点相同的点的下标,\(nxt\)表示下一个跟这个点相同的点的下标。
这样子就变成求立方体最大点值了,我们可以果断树套树套树走一波,然后获得\(TLE\)的好成绩。
所以我们得用一些神奇的手段降低问题的维度。
而这个手段就是可持久化。
我们按\(lst\)从小到大在\(nxt\)值域范围内建立可持久化线段树,内套位置线段树维护区间最大值即可。
时间复杂度:\(O(nlog^2n)\)
空间复杂度:\(O(nlog^2n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
int n,m,lstans;
int rt[maxn],tmp[maxn];
int pos[maxn],a[maxn],lst[maxn],nxt[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Project {
int lst,nxt,pos,val;
Project() {}
Project(int _lst,int _nxt,int _pos,int _val) {
lst=_lst,nxt=_nxt,pos=_pos,val=_val;
}
bool operator<(const Project &a)const {
return lst<a.lst;
}
}p[maxn];
struct pos_chairman_tree {
int tot;
struct tree_node {
int ls,rs,mx;
}tree[maxn*18*18];
void change(int &p,int lst,int l,int r,Project node) {
p=++tot;tree[p]=tree[lst];
tree[p].mx=max(tree[p].mx,node.val);
if(l==r)return;
int mid=(l+r)>>1;
if(node.pos<=mid)change(tree[p].ls,tree[lst].ls,l,mid,node);
else change(tree[p].rs,tree[lst].rs,mid+1,r,node);
}
int query(int p,int l,int r,int L,int R) {
if(L<=l&&r<=R)return tree[p].mx;
int mid=(l+r)>>1,res=0;
if(L<=mid)res=max(res,query(tree[p].ls,l,mid,L,R));
if(R>mid)res=max(res,query(tree[p].rs,mid+1,r,L,R));
return res;
}
}T2;
struct lst_chairman_tree {
int tot;
struct tree_node {
int ls,rs,rt;
}tree[maxn*18];
void change(int &p,int lst,int l,int r,Project node) {
p=++tot;tree[p]=tree[lst];
T2.change(tree[p].rt,tree[lst].rt,1,n,node);
if(l==r)return;
int mid=(l+r)>>1;
if(node.nxt<=mid)change(tree[p].ls,tree[lst].ls,l,mid,node);
else change(tree[p].rs,tree[lst].rs,mid+1,r,node);
}
int query(int p,int l,int r,int L,int R) {
if(!p)return 0;
if(l>R)return T2.query(tree[p].rt,1,n,L,R);
int mid=(l+r)>>1,res=query(tree[p].rs,mid+1,r,L,R);
if(R+1<=mid)res=max(res,query(tree[p].ls,l,mid,L,R));
return res;
}
}T1;
int main() {
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read(),lst[i]=pos[a[i]],pos[a[i]]=i;
for(int i=1;i<=n;i++)pos[i]=n+1;
for(int i=n;i;i--)nxt[i]=pos[a[i]],pos[a[i]]=i;
for(int i=1;i<=n;i++)p[i]=Project(lst[i],nxt[i],i,a[i]);
sort(p+1,p+n+1);
for(int i=1;i<=n;i++) {
tmp[i]=p[i].lst;
T1.change(rt[i],rt[i-1],2,n+1,p[i]);
}
for(int i=1;i<=m;i++) {
int l=(read()+lstans)%n+1,r=(read()+lstans)%n+1;
if(r<l)swap(l,r);
int pos=lower_bound(tmp+1,tmp+n+1,l)-tmp-1;
lstans=T1.query(rt[pos],2,n+1,l,r);
printf("%d\n",lstans);
}
return 0;
}