【题解】[bzoj 4358] permu【单增莫队】

题目链接

题意

给定排列 \(p\)\(Q\) 次询问 \(p[l..r]\) 的最长值域连续段的长度。

\(1\leq n,m\leq 5\times 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\n",res[i]);
}

posted @ 2021-01-08 14:34  破壁人五号  阅读(98)  评论(0编辑  收藏  举报