• [BZOJ4241]历史研究(回滚莫队)


    将整个序列分成$sqrt{n}$块,所有询问按左端点所在块为第一关键字,右端点所在块为第二关键字排序。

    当右端点增加或左端点减小时,更新桶与答案。但是左端点增加时需要删除,这时就必须用堆等数据结构维护,复杂度多一个log。

    回滚莫队是一个trick:

    1.按同样的方法对所有询问排序,每次处理左端点在同一个块中的所有询问。

    2.若对于当前询问,右端点和左端点在同一个块中,暴力即可。

    3.否则,右端点照常加入更新,左端点先设为块尾,再不断减小,更新答案后再还原至块尾。

    这样每次只有左端点减小时才会更新答案,不再需要删除操作。

    复杂度分析基本与普通莫队相同。

    对于左右端点所属块相同的询问,单次复杂度显然$O(sqrt{n})$

    对于左右端点所属块不同的询问,右端点的处理并没有区别,故总复杂度仍是$(nsqrt{n})$。左端点每次都只在一个块中移动,故总复杂度也是$(nsqrt{n})$

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=100010,B=300;
     9 ll ans[N];
    10 int n,Q,cnt[N],a[N],b[N],bel[N];
    11 struct P{ int l,r,id; }q[N];
    12 bool cmp(const P &a,const P &b){ return (bel[a.l]==bel[b.l]) ? a.r<b.r : bel[a.l]<bel[b.l]; }
    13 
    14 int main(){
    15     freopen("bzoj4241.in","r",stdin);
    16     freopen("bzoj4241.out","w",stdout);
    17     scanf("%d%d",&n,&Q);
    18     rep(i,1,n) scanf("%d",&a[i]),b[i]=a[i],bel[i]=(i-1)/B+1;
    19     rep(i,1,Q) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    20     sort(b+1,b+n+1); int tot=unique(b+1,b+n+1)-b-1;
    21     rep(i,1,n) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
    22     sort(q+1,q+Q+1,cmp); int i,j;
    23     for (i=1; i<=Q; i=j){
    24         int t=bel[q[i].l],r=min(n,B*t),l=r+1; ll mx=0;
    25         memset(cnt,0,sizeof(cnt));
    26         for (j=i; j<=Q && bel[q[j].l]==t; j++){
    27             if (bel[q[j].r]==t){
    28                 rep(k,q[j].l,q[j].r) cnt[a[k]]++,mx=max(mx,1ll*b[a[k]]*cnt[a[k]]);
    29                 rep(k,q[j].l,q[j].r) cnt[a[k]]--;
    30                 ans[q[j].id]=mx; mx=0;
    31             }else{
    32                 while (r<q[j].r) cnt[a[++r]]++,mx=max(mx,1ll*b[a[r]]*cnt[a[r]]);
    33                 ll tmp=mx;
    34                 while (l>q[j].l) cnt[a[--l]]++,mx=max(mx,1ll*b[a[l]]*cnt[a[l]]);
    35                 ans[q[j].id]=mx;
    36                 while (l<=B*t) cnt[a[l++]]--;
    37                 mx=tmp;
    38             }
    39         }
    40     }
    41     rep(i,1,Q) printf("%lld
    ",ans[i]);
    42     return 0;
    43 }

     

  • 相关阅读:
    airodump-ng的使用及显示
    bash shell 遍历一个数组
    cisco 交换机 IOS命令
    apt-key Debian packages密钥管理命令
    find命令的用法
    bash的快捷键
    groff编写man页
    tcpdump软件使用
    vue 项目常见功能(搜索 时间戳转换 过滤器)
    vue2.0 常见功能 (v-for 配置路由 组件渲染)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9897941.html
Copyright © 2020-2023  润新知