ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

数据结构 | 回滚莫队浅记

2022-02-27 09:01:05  阅读:220  来源: 互联网

标签:回滚 const 询问 sqrt tmpans 例题 莫队 浅记


前置知识

之前写的普通莫队笔记,在这里当个前置知识,其实大约知道莫队大概就是把询问离线下来分块并排序之后用两个指针 \(l,r\) 来更新信息统计答案即可。

有时在区间转移的时候,有些删除或添加的操作无法实现,那么当只有一种操作不能实现的时候,就可以用莫队来解决这个问题,然而普通莫队是很难解决(或者说是不能解决)这个问题的,所以我们要对普通莫队进行改造,也就是回滚莫队。

本文出现所有代码缺省源使用V5.3.

「例题一」洛谷模板

原题链接:P5906 【模板】回滚莫队&不删除莫队

「例题一」题目简述

给定一个序列,多次询问一段区间 \([l,r]\),求区间中相同的数的最远间隔距离。

序列中两个元素的间隔距离指的是两个元素下标差的绝对值。

「例题一」思路简述

首先来说这个题有什么操作不能实现。显然增加是好实现的,只需要每次在增加时更新距离信息(记录第一次出现和最后一次出现)即可。但是删除操作不能这样实现,因为在删除的时候若要更新答案,需要知道次大值……肯定是不能这样维护的,所以我们要让 \(l\) 和 \(r\) 在移动的过程中尽量避免删除操作,也就是尽量让 \(l\) 向左端移动,\(r\) 向右端移动。

那么我们每次枚举块,把块内的询问解决的时候,每次把 \(l\) 拉回当前块的右端,然后保证 \(r\) 只向右端移动,\(l\) 不断根据询问反复横跳,对于在一个块内的询问暴力更新(复杂度 \(O(\sqrt{n})\),不过可能实际略大),否则跳两个指针更新答案。因为块的是 \(O(\sqrt{n})\) 的,所以对于每个询问,\(l\) 的移动是 \(O(\sqrt{n})\) 的,所以这样做的复杂度就是 \(O(n\sqrt{m}).\)

「例题一」Code


template<typename J>
I J Hmax(const J &x,const J &y) {
    Heriko x>y?x:y;
}

template<typename J>
I J Hmin(const J &x,const J &y) {
    Heriko x<y?x:y;
}

CI MXX(2e5+1);

int ans[MXX],a[MXX],b[MXX],n,blo[MXX],len,blocnt,qn,appeared[MXX],fstpos[MXX],lstpos[MXX],apn;

struct Query {
    int l,r,id;

    I bool operator < (const Query &co) const {
        Heriko (blo[l]==blo[co.l])?(r<co.r):(blo[l]<blo[co.l]);
    }
}

q[MXX];

int lst[MXX];

I int Clac_Faster_Than_SF1000(int l,int r) {
    int res(0);

    for(int i(l);i<=r;++i)
        lst[a[i]]=0;

    for(int i(l);i<=r;++i)
        if(!lst[a[i]])
            lst[a[i]]=i;
        else
            res=Hmax(res,i-lst[a[i]]);  

    Heriko res;
}

S main() {
    Files();

    fr(n),len=sqrt(n);

    for(int i(1);i<=n;++i)
        fr(a[i]),b[i]=a[i];

    sort(b+1,b+1+n);
    int nl(unique(b+1,b+1+n)-b-1);

    for(int i(1);i<=n;++i)
        a[i]=lower_bound(b+1,b+1+nl,a[i])-b;

    for(int i(1);i<=n;++i)
        blo[i]=(i-1)/len+1;

    blocnt=blo[n];

    fr(qn);

    for(int i(1);i<=qn;++i)
        fr(q[i].l),fr(q[i].r),q[i].id=i;

    sort(q+1,q+1+qn);
    int l(0),r(0),nw(1),tmpans(0);

    for(int i(1);i<=blocnt;++i) {
        int rx(Hmin(n,i*len));
        l=rx+1,r=rx,tmpans=0,apn=0;

        for(;blo[q[nw].l]==i;++nw) {
            if(blo[q[nw].r]==i)
                ans[q[nw].id]=Clac_Faster_Than_SF1000(q[nw].l,q[nw].r);
            else {
                while(r<q[nw].r) {
                    ++r;
                    lstpos[a[r]]=r;

                    if(!fstpos[a[r]])
                        fstpos[a[r]]=r,appeared[++apn]=a[r];

                    tmpans=Hmax(tmpans,r-fstpos[a[r]]);
                }

                int lsttmp(tmpans);

                while(l>q[nw].l) {
                    --l;

                    if(lstpos[a[l]])
                        tmpans=Hmax(tmpans,lstpos[a[l]]-l);
                    else
                        lstpos[a[l]]=l;
                }

                ans[q[nw].id]=tmpans;

                while(l<=rx) {
                    if(lstpos[a[l]]==l)
                        lstpos[a[l]]=0;

                    ++l;
                }

                tmpans=lsttmp;
            }
        }

        for(int i(1);i<=apn;++i)
            fstpos[appeared[i]]=lstpos[appeared[i]]=0;
    }

    for(int i(1);i<=qn;++i)
        fw(ans[i],1);

    Heriko Deltana;
}

「例题二」AT1219 歴史の研究

原题链接:AtCoder-JOI2014 歴史の研究

洛谷链接:AT1219 歴史の研究

「例题二」题目简述

给出长度为 \(N\) 的序列,\(Q\) 次询问,每次询问区间 \([L,R]\) 中最大的重要度。

重要度的定义为当前事件的权值 \(X_i\) 乘上事件在区间中出现次数 \(T_i.\)

「例题二」思路简述

和上个题一样,这个题添加操作也是很好实现的,维护一个桶即可,删除操作一样的不能实现,所以我们用同样的策略。

「例题二」Code

template<typename J>
I J Hmax(const J &x,const J &y) {
    Heriko x>y?x:y;
}

template<typename J>
I J Hmin(const J &x,const J &y) {
    Heriko x<y?x:y;
}

CI MXX(2e5+1);

int a[MXX],b[MXX],lx[MXX],rx[MXX],blo[MXX],n,qn,len,blocnt,cnt[MXX],co[MXX];

LL ans[MXX],tmpans;

struct Query {
    int l,r,id;

    I bool operator < (const Query &co) const {
        Heriko blo[l]==blo[co.l]?r<co.r:l<co.l;
    }
}

q[MXX];

I void Add(int x) {
    ++cnt[a[x]];
    tmpans=Hmax(tmpans,(LL)cnt[a[x]]*b[a[x]]);
}

S main() {
    Files();

    fr(n),fr(qn),len=sqrt(n),blocnt=n/len;

    for(int i(1);i<=n;++i)
        fr(a[i]),b[i]=a[i];

    for(int i(1);i<=qn;++i)
        fr(q[i].l),fr(q[i].r),q[i].id=i;

    sort(b+1,b+1+n);
    int nl(unique(b+1,b+1+n)-b-1);

    for(int i(1);i<=n;++i)
        a[i]=lower_bound(b+1,b+1+nl,a[i])-b;

    for(int i(1);i<=n;++i)
        blo[i]=(i-1)/len+1;

    for(int i(1);i<=blocnt;++i)
        lx[i]=rx[i-1]+1,rx[i]=lx[i]+len-1;

    if(rx[blocnt]<n)
        ++blocnt,lx[blocnt]=rx[blocnt-1]+1,rx[blocnt]=n;//这里用了一种和前面不同的处理每个块端点的方法,都不难写

    int l(0),r(0),nw(1);
    sort(q+1,q+1+qn);

    for(int i(1);i<=blocnt;++i) {
        mst(cnt,0);
        r=rx[i],tmpans=0;

        while(blo[q[nw].l]==i) {
            l=rx[i]+1;

            if(q[nw].r-q[nw].l<=len) {
                
                mst(co,0);
                LL anothertmpans(0);

                for(int i(q[nw].l);i<=q[nw].r;++i)
                    ++co[a[i]];

                for(int i(q[nw].l);i<=q[nw].r;++i)
                    anothertmpans=Hmax(anothertmpans,(LL)co[a[i]]*b[a[i]]);

                for(int i(q[nw].l);i<=q[nw].r;++i)
                    --co[a[i]];

                ans[q[nw].id]=anothertmpans;
            }
            else {
                while(q[nw].r>r)
                    Add(++r);

                LL lsttmp(tmpans);

                while(q[nw].l<l)
                    Add(--l);

                ans[q[nw].id]=tmpans;
                tmpans=lsttmp;

                while(l<=rx[i])
                    --cnt[a[l++]];
            }

            ++nw;
        }
    }

    for(int i(1);i<=qn;++i)
        fw(ans[i],1);

    Heriko Deltana;
}

终了

终了。

标签:回滚,const,询问,sqrt,tmpans,例题,莫队,浅记
来源: https://www.cnblogs.com/HRiver2/p/HR2note70.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有