zoukankan      html  css  js  c++  java
  • 回滚莫队

    原理

    对于删除操作的贡献很难统计的修改 可以选择使用回滚莫队

    比如要求区间最值

    显然Max运算无法撤销 考虑如何快速处理删除贡献的操作

    处理不了 所以换种思路 不再删除贡献

    首先在莫队的sort时候 按照第一维bel,第二维r排序

    此时对于每个左端点在同一个块内的询问, 此时r单调递增

    所以对于r是没有删除操作的

    考虑在块内无序排列的l 其实每次从块的右端点往左开始跑就可以了

    每次暴力统计从块的右端点到l的贡献

    因为块长不超过(√N) 所以每次暴力处理复杂度也是根号的

    所以总复杂度(N√N)

    当左右端点都在同一个块内时直接暴力即可

    例题:

    A:历史研究

    求区间最值

    维护块右端点右边每个事件出现的次数 (cnt[x]) 最大值Mx

    维护块内每个事件出现次数 (tmp[x]) 最大值Max

    对于询问 先把右端点转移到合适的位置 维护cnt与Mx

    然后从块的右端点开始往左跑 每次维护tmp 与Max

    当前事件的贡献就是((cnt[x] + tmp[x]) * x)

    每次处理完将tmp清空就好了




    B:permu

    求区间最大连续段长度

    删除操作不好处理 一样考虑回滚

    在块的右端点右边维护 ld[x],l[x],rd[x],r[x] 分别表示x这个数向左最多多少长度是连续的, 最左边的数是多少,右边同理

    以及此时的答案

    在块内维护 tmpld[x],tmpl[x],tmprd[x],tmpr[x] 定义与块右边的相同

    然后转移就可以了 每次加入一个新数 用左右两边的数更新它,再用它更新左右两边的值

    tmp处理的时候有个细节是 如果此时tmpl[x-1]没有值, 需要用l[x-1]更新, r同理

    每次更新维护答案 得解

    复杂度 (N√N) 但是没有跑过(N√Nlog_N) 维护东西太多导致常数太大了
    (C++ NOI (N√NlogN)跑不过去,这个能跑

    (细节挺多但是一遍过了

    显示代码

    include<bits/stdc++.h>

    using namespace std;

    define rint register int

    const int maxn = 1e5 + 10;
    int tld[maxn],trd[maxn],tl[maxn],tr[maxn];
    int l[maxn],r[maxn],ld[maxn],rd[maxn];
    int stl[maxn],str[maxn];
    int ans[maxn];
    int a[maxn];
    int Mx,sqr,cur,top1,top2;

    struct node{
    int l,r,bel,id;
    friend bool operator <(const node &A,const node &B) {return A.bel == B.bel ? A.r < B.r : A.bel < B.bel;}
    }q[maxn];

    int main(){
    rint n,m; scanf("%d%d",&n,&m); sqr = sqrt(n);
    for(rint i = 1;i <= n;++i) scanf("%d",&a[i]);
    for(rint i = 1;i <= m;++i) scanf("%d%d",&q[i].l,&q[i].r),q[i].bel = (q[i].l - 1) / sqr + 1, q[i].id = i;
    sort(q+1,q+m+1);
    rint tail = 0;
    for(rint i = 1;i <= m;++i) {
    rint L = q[i].l,R = q[i].r;
    if(q[i].bel != q[i-1].bel) {
    memset(l,0,sizeof(l)); memset(ld,0,sizeof(ld));
    memset(r,0,sizeof(r)); memset(rd,0,sizeof(rd));
    tail = q[i].bel * sqr; Mx = 0;
    }
    if(R <= q[i].bel * sqr) {
    cur = 0;
    for(rint j = L;j <= R;++j) {
    tld[a[j]] = tld[a[j]-1] + 1;
    trd[a[j]] = trd[a[j]+1] + 1;
    tl[a[j]] = tld[a[j]-1] ? tl[a[j]-1] : a[j];
    tr[a[j]] = trd[a[j]+1] ? tr[a[j]+1] : a[j];
    if(tld[a[j]-1]) trd[tl[a[j]-1]] += trd[a[j]], tr[tl[a[j]-1]] = tr[a[j]];
    if(trd[a[j]+1]) tld[tr[a[j]+1]] += tld[a[j]], tl[tr[a[j]+1]] = tl[a[j]];
    cur = max(cur,tld[tr[a[j]]]);
    }
    for(rint j = L;j <= R;++j) tld[a[j]] = trd[a[j]] = tl[a[j]] = tr[a[j]] = 0;
    ans[q[i].id] = cur;
    continue;
    }
    while(tail < R) {
    ++tail;
    ld[a[tail]] = ld[a[tail]-1] + 1;
    rd[a[tail]] = rd[a[tail]+1] + 1;
    l[a[tail]] = ld[a[tail]-1] ? l[a[tail]-1] : a[tail];
    r[a[tail]] = rd[a[tail]+1] ? r[a[tail]+1] : a[tail];
    if(ld[a[tail]-1]) rd[l[a[tail]-1]] += rd[a[tail]], r[l[a[tail]-1]] = r[a[tail]];
    if(rd[a[tail]+1]) ld[r[a[tail]+1]] += ld[a[tail]], l[r[a[tail]+1]] = l[a[tail]];
    Mx = max(Mx,ld[r[a[tail]]]);
    }
    cur = Mx;
    for(rint j = L;j <= q[i].bel * sqr;++j) {
    tld[a[j]] = (tld[a[j]-1] ? tld[a[j]-1] : ld[a[j]-1]) + 1;
    trd[a[j]] = (trd[a[j]+1] ? trd[a[j]+1] : rd[a[j]+1]) + 1;
    tl[a[j]] = (tld[a[j]-1] ? tld[a[j]-1] : ld[a[j]-1]) ? (tl[a[j]-1] ? tl[a[j]-1] : l[a[j]-1]) : a[j];
    tr[a[j]] = (trd[a[j]+1] ? trd[a[j]+1] : rd[a[j]+1]) ? (tr[a[j]+1] ? tr[a[j]+1] : r[a[j]+1]) : a[j];
    if(tld[a[j]-1] + ld[a[j]-1]) {
    stl[++top1] = tl[a[j]-1] ? tl[a[j]-1] : l[a[j]-1];
    rint x = stl[top1];
    trd[x] = (trd[x] ? trd[x] : rd[x]) + trd[a[j]], tr[x] = tr[a[j]];
    }
    if(trd[a[j]+1] + rd[a[j]+1]) {
    str[++top2] = tr[a[j]+1] ? tr[a[j]+1] : r[a[j]+1];
    rint x = str[top2];
    tld[x] = (tld[x] ? tld[x] : ld[x]) + tld[a[j]], tl[x] = tl[a[j]];
    }
    cur = max(cur,tld[tr[a[j]]]);
    }
    for(rint j = L;j <= q[i].bel*sqr;++j) tld[a[j]] = trd[a[j]] = tl[a[j]] = tr[a[j]] = 0;
    while(top1) {
    rint x = stl[top1];
    trd[x] = tr[x] = 0;
    top1--;
    }
    while(top2) {
    rint x = str[top2];
    tld[x] = tl[x] = 0;
    top2--;
    }
    ans[q[i].id] = cur;
    }
    for(rint i = 1;i <= m;++i) printf("%d ",ans[i]);
    return 0;
    }

    如初见 与初见
  • 相关阅读:
    自定义控件其实很简单5/12
    自定义控件其实很简单1/3
    自定义控件其实很简单1/4
    自定义控件其实很简单1/6
    ListView addfooter 没显示 footer的原因(之一)
    android 版本和 api level 的对应关系
    derby入门
    OA系统与ERP的区别
    Windows下的定时任务
    linux学习笔记——安装问题
  • 原文地址:https://www.cnblogs.com/HISKrrr/p/14262767.html
Copyright © 2011-2022 走看看