• [BZOJ4540]序列


    给出一个序列,求某段区间的位置不同子串的最小值之和

    对于前$40%$,我们可以$n^{2}$预处然后$O(nsqrt{n})$

    预处理中$zzz[i][j]$表示以$i$开头,结尾最长到$j$的前缀子串的最小值之和

    同理$fff[i][j]$表示倒过来的情况

    考虑对预处理进行优化

    对于一个区间$[l,r]$,以$l$开头,结尾最长到$r$的前缀可分为两部分计算,

    设$x$为区间$[l,r]$中最小值所在位置

     对于结尾在区间$[x,r]$中的子串,对答案的贡献为$A[x]*(r-x+1)$

    对于结尾在区间$[l,x)$中的子串,我们先找到下一个比$A[l]$小的位置$p1$,则对于结尾在区间$[l,p1)$中的子串,对答案的贡献为$A[l]*(p1-l)$,再找到下一个比$A[p1]$小的位置$p2$类推,直到找到$x$为止

    这就相当于对于一个数$A[x]$,我们把下一个比它小的数$A[y]$向它连边,边权为$A[x]*(y-x)$,然后求树上的节点$l$到$x$的距离和

    这个过程我们可以通过维护单调栈预处理出来

    $zzz[i]$表示节点到$i$所属的树根的距离,因为可能是森林

    从后往前枚举,当前值小于等于栈顶时弹栈,然后$zzz[i]=zzz[sta[top]]+A[i]*(sta[top]-i)$

    $fff[i]$同理

    然后莫队,,,复杂度$O(nlogn+nsqrt{n})$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 #define maxn 100005
     5 typedef long long ll;
     6 struct node{ int l,r,blc,id; ll ans; }q[maxn];
     7 int n,m,sta[maxn],mn[maxn<<1][20],log_2[maxn];
     8 ll A[maxn],fff[maxn],zzz[maxn];
     9 bool cmp1(node a,node b){
    10     if(a.blc!=b.blc)return a.blc<b.blc;
    11     else if(a.r!=b.r)return a.r<b.r;
    12     else return a.l<b.l;
    13 }
    14 bool cmp2(node a,node b){ return a.id<b.id; }
    15 void PP(){
    16     int top=0;
    17     for(int i=1;i<=n;i++){
    18         while(top&&A[i]<=A[sta[top]])top--;
    19         fff[i]=fff[sta[top]]+A[i]*(i-sta[top]);
    20         sta[++top]=i;
    21     }
    22     sta[top=0]=n+1;
    23     for(int i=n;i;i--){
    24         while(top&&A[i]<=A[sta[top]])top--;
    25         zzz[i]=zzz[sta[top]]+A[i]*(sta[top]-i);
    26         sta[++top]=i;
    27     }
    28 }
    29 int Min(int x,int y){
    30     return A[x]<A[y]?x:y;
    31 }
    32 void build_ST(){
    33     A[0]=inf;
    34     for(int i=1;i<=n;i++)
    35         mn[i][0]=i;
    36     log_2[1]=0;
    37     for(int i=2;i<=n;i++)
    38         log_2[i]=log_2[i>>1]+1;
    39     for(int j=1;j<=log_2[n];j++)
    40         for(int i=1;i<=n;i++)
    41             mn[i][j]=Min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    42 }
    43 int query_ST(int l,int r){
    44     int len=log_2[r-l+1];
    45     return Min(mn[l][len],mn[r-(1<<len)+1][len]);
    46 }
    47 ll call(int l,int r){
    48     int x=query_ST(l,r);
    49     return A[x]*(r-x+1)+zzz[l]-zzz[x];
    50 }
    51 ll calr(int l,int r){
    52     int x=query_ST(l,r);
    53     return A[x]*(x-l+1)+fff[r]-fff[x];
    54 }
    55 void MD(){
    56     sort(q+1,q+1+m,cmp1);
    57     int l=1,r=0;
    58     ll ans=0;
    59     for(int i=1;i<=m;i++){
    60         while(r<q[i].r)ans+=calr(l,++r);
    61         while(r>q[i].r)ans-=calr(l,r--);
    62         while(l>q[i].l)ans+=call(--l,r);
    63         while(l<q[i].l)ans-=call(l++,r);
    64         q[i].ans=ans;
    65     }
    66     sort(q+1,q+1+m,cmp2);
    67     for(int i=1;i<=m;i++)
    68         printf("%lld
    ",q[i].ans);
    69 }
    70 int main(){
    71     scanf("%d%d",&n,&m);
    72     for(int i=1;i<=n;i++)
    73         scanf("%lld",&A[i]);
    74     PP(),build_ST();
    75     int block=sqrt(n);
    76     for(int i=1;i<=m;i++){
    77         scanf("%d%d",&q[i].l,&q[i].r);
    78         q[i].blc=(q[i].l-1)/block+1,q[i].id=i;
    79     }
    80     MD();
    81     return 0;
    82 }
    View Code
  • 相关阅读:
    仪仗队
    疫情控制
    Code
    距离咨询
    舒适的路线
    桐桐的糖果计划
    跑路
    最短路计数
    骑马修栅栏
    搭桥
  • 原文地址:https://www.cnblogs.com/Ngshily/p/5409337.html
Copyright © 2020-2023  润新知