题意
给定排列 (p),(Q) 次询问 (p[l..r]) 的最长值域连续段的长度。
(1leq n,mleq 5 imes 10^4)
题解
记录每个值域连续段的端点往左/右能延伸的最大距离,往 (p[l,r]) 中加入一个数时可以 (O(1)) 维护。于是可以单增莫队。
(单增莫队做法:(l,r) 在同一块的直接暴力,其他询问按照 (l) 所在块(([L,R]))分组,每一组按 (r) 从小到大排序;处理时从 ([R,r]) 转移到 ([R,r']),再转移到 ([l',r']) 得到答案,最后回滚到 ([R,r']))
#include<bits/stdc++.h>
using namespace std;
int getint(){
int ans=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans;
}
const int N=1e5+10;
int n,m,blk;
int p[N];
struct query{
int l,r,id;
};
bool cmp(const query &a,const query &b){ return a.r<b.r; }
vector<query>q[N];
int xl[N],xr[N];
vector<pair<int,int> >lm,rm;
int ans=0,oldans=0;
void addl(int x){
int v=p[x];
lm.emplace_back(v,xl[v]);
rm.emplace_back(v,xr[v]);
xl[v]=xl[v-1]?xl[v-1]:v;
xr[v]=xr[v+1]?xr[v+1]:v;
ans=max(ans,xr[v]-xl[v]+1);
if(xl[v-1]){
rm.emplace_back(xl[v-1],xr[xl[v-1]]);
xr[xl[v-1]]=xr[v];
}
if(xr[v+1]){
lm.emplace_back(xr[v+1],xl[xr[v+1]]);
xl[xr[v+1]]=xl[v];
}
}
void addr(int x){
int v=p[x];
xl[v]=xl[v-1]?xl[v-1]:v;
xr[v]=xr[v+1]?xr[v+1]:v;
ans=max(ans,xr[v]-xl[v]+1);
if(xl[v-1])
xr[xl[v-1]]=xr[v];
if(xr[v+1])
xl[xr[v+1]]=xl[v];
}
void rollback(){
ans=oldans;
for(int i=rm.size()-1;i>=0;--i)xr[rm[i].first]=rm[i].second;
for(int i=lm.size()-1;i>=0;--i)xl[lm[i].first]=lm[i].second;
rm.clear();
lm.clear();
}
int res[N];
int main(){
n=getint(),m=getint();
blk=max(1.0,n/sqrt(m*0.7));
for(int i=1;i<=n;i++)p[i]=getint();
for(int i=0;i<m;i++){
int l=getint(),r=getint();
if(l/blk==r/blk){
for(int i=r;i>=l;--i)addl(i);
res[i]=ans;
rollback();
continue;
}
query t;t.l=l;t.r=r;t.id=i;
q[l/blk].push_back(t);
}
for(int i=0;i<=n/blk;i++){
sort(q[i].begin(),q[i].end(),cmp);
memset(xl,0,sizeof(int)*(n+1));
memset(xr,0,sizeof(int)*(n+1));
ans=0;
int r=(i+1)*blk-1,l=r;
for(auto q: ::q[i]){
while(r<q.r)++r,addr(r);
oldans=ans;
for(int i=l;i>=q.l;--i)addl(i);
res[q.id]=ans;
rollback();
}
}
for(int i=0;i<m;i++)printf("%d
",res[i]);
}