【模板】回滚莫队&不删除莫队

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int N=2e5+10;
int n,m,len;//len代表块大小
int a[N],b[N];
//a是离散化后的数组
//b是元素属于的块
int R[N];//每个块的右端
int ans[N];//答案
int st[N],ed[N],ed2[N];
//st代表元素第一次出现的位置
//ed代表元素出现的最后一次的位置
//ed2代表每组询问的公共起点前的一段中,元素出现的最后一个位置
struct node{int id,x;}tmp[N];
struct query{int l,r,id;}q[N];
bool cmp1(node x,node y){return x.x<y.x;}
//如果左端点块相同,优先按照右端点排序,否则按照左端点所在块进行排序
bool cmp2(query x,query y){return b[x.l]==b[y.l]?x.r<y.r:b[x.l]<b[y.l];}

void data()
{
    cin >>n;
    len=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        cin >>tmp[i].x;
        tmp[i].id=i;
        b[i]=(i-1)/len+1;
    }
    for(int i=1;i<=n;i++) R[i]=(i==b[n])?n:len*i;
    cin >>m;
    for(int i=1;i<=m;i++)
    {
        cin >>q[i].l>>q[i].r;
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp2);
}

void tmp_()//离散化
{
    sort(tmp+1,tmp+n+1,cmp1);
    int pre=-1,cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(tmp[i].x!=pre) cnt++;
        a[tmp[i].id]=cnt;
        pre=tmp[i].x;
    }
}

void work()
{
    int block=0,tmp1=0,l=0,r=0;
    //block代表上次询问的左端点属于哪个块
    //如果块一样就使用上次留下来的进程
    //否则就重新计算
    //tmp1代表公共L到上一次询问的R得到的答案
    //l公共L
    //r上一次询问的R
    for(int i=1;i<=m;i++)
    {
        if(b[q[i].l]==b[q[i].r])//如果同属一个块,直接暴力求解
        {
            tmp1=0;
            for(int j=q[i].l;j<=q[i].r;j++) st[a[j]]=0;
            for(int j=q[i].l;j<=q[i].r;j++)
            {
                if(!st[a[j]]) st[a[j]]=j;
                tmp1=max(tmp1,j-st[a[j]]);
            }
            for(int j=q[i].l;j<=q[i].r;j++) st[a[j]]=0;
            ans[q[i].id]=tmp1;
            continue;
        }
        int now=b[q[i].l];//记录左端点所在块
        if(block!=now)//左端点所在块发生改变
        {
            tmp1=0;
            for(int j=l;j<=r;j++) st[a[j]]=ed[a[j]]=0;//直接清空
            l=R[now];//先在now所在块的下一个块进行计算,最后再处理不完整的块
            r=l-1;
            block=now;//更新所在块
        }
        while(r<q[i].r)
        {
            r++;
            if(!st[a[r]]) st[a[r]]=r;//元素第一次出现位置
            ed[a[r]]=r;//更新最后一次出现位置
            tmp1=max(tmp1,r-st[a[r]]);
        }
        int p=l,tmp2=0;//开始处理不完整的块
        while(q[i].l<p)
        {
            p--;
            if(!ed2[a[p]]) ed2[a[p]]=p;//从后往前更新
            tmp2=max(tmp2,max(ed[a[p]],ed2[a[p]])-p);//p最后出现的位置可能存在公共L的右端所以要取max
        }
        while(p<l)
        {
            ed2[a[p]]=0;
            p++;
        }
        ans[q[i].id]=max(tmp2,tmp1);
    }
}

signed main()
{
    data();
    tmp_();
    work();
    for(int i=1;i<=m;i++) cout <<ans[i]<<'\n';
    return 0;
}

posted @ 2026-08-13 19:58  W_x_ye  阅读(2)  评论(0)    收藏  举报