• bzoj4540 [Hnoi2016]序列


    Description

      给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。

    Input

      输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。

    Output

      对于每次询问,输出一行,代表询问的答案。

    Sample Input

    5 5
    5 2 4 1 3
    1 5
    1 3
    2 4
    3 5
    2 5

    Sample Output

    28
    17
    11
    11
    17

    HINT

    1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9

    正解:莫队算法+$ST$表+单调栈。

    一个只用过一次的数据结构,一个从没用过的数据结构。。

    首先,这道题允许离线,于是我们想到莫队算法。

    我们考虑移动右端点$r$,能产生多少贡献。当我们移动端点以后,我们能够产生的贡献就是$(r-last+1)*a[r]$,其中$last$为$r$左边比它小的第一个元素。那么我们可以用单调栈$O(n)$地预处理出左边比它小的第一个数的位置和右边比它小的第一个数的位置。然后我们在查询时,可以一路往左边跳,并计算贡献,直到跳到这个区间的最后一个数,而这个数肯定是这个区间最小的数。那么我们可以考虑用$ST$表,记录一个区间中最小数的出现位置。同时,我们记录一个类似于前缀和的东西,记录出贡献的前缀和,即$suml[r]=suml[last[r]]+(r-last[r])*a[r]$。然后我们就可以$O(1)$地查询了。同样,移动左端点与移动右端点类似。

    话说这道题还是我的$ST$表入门题呢。。

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <complex>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <cstdio>
     8 #include <vector>
     9 #include <cmath>
    10 #include <queue>
    11 #include <stack>
    12 #include <map>
    13 #include <set>
    14 #define inf (1<<30)
    15 #define N (500010)
    16 #define il inline
    17 #define RG register
    18 #define ll long long
    19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    20 
    21 using namespace std;
    22 
    23 struct data{ ll i,l,r; }q[N];
    24 
    25 ll a[N],st[N],lg[N],bl[N],lst[N],nxt[N],suml[N],sumr[N],ans[N],ST[19][N],n,Q,L,R,Ans,top,block;
    26 
    27 il ll gi(){
    28     RG ll x=0,q=1; RG char ch=getchar();
    29     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    30     if (ch=='-') q=-1,ch=getchar();
    31     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    32     return q*x;
    33 }
    34 
    35 il ll cmp(const data &a,const data &b){
    36     if (bl[a.l]==bl[b.l]) return a.r<b.r;
    37     return bl[a.l]<bl[b.l];
    38 }
    39 
    40 il void buildST(){
    41     for (RG ll i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
    42     for (RG ll j=1;j<=17;++j)
    43     for (RG ll i=1;i<=n;++i){
    44         RG ll t=i+(1<<(j-1));
    45         ST[j][i]=a[ST[j-1][i]]<=a[ST[j-1][t]] ? ST[j-1][i] : ST[j-1][t];
    46     }
    47     return;
    48 }
    49 
    50 il ll query(RG ll l,RG ll r){
    51     RG ll t=lg[r-l+1],c=r-(1<<t)+1;
    52     return a[ST[t][l]]<=a[ST[t][c]] ? ST[t][l] : ST[t][c];
    53 }
    54 
    55 il void updatel(RG ll l,RG ll r,RG ll fg){
    56     RG ll x=query(l,r),res=sumr[l]-sumr[x]+(r-x+1)*a[x];
    57     Ans+=fg*res; return;
    58 }
    59 
    60 il void updater(RG ll l,RG ll r,RG ll fg){
    61     RG ll x=query(l,r),res=suml[r]-suml[x]+(x-l+1)*a[x];
    62     Ans+=fg*res; return;
    63 }
    64 
    65 il void work(){
    66     n=gi(),Q=gi(),block=sqrt(n),st[top=1]=1;
    67     for (RG ll i=1;i<=n;++i) a[i]=gi(),ST[0][i]=i,bl[i]=(i-1)/block+1;
    68     for (RG ll i=2;i<=n;++i){
    69     while (top && a[st[top]]>=a[i]) nxt[st[top--]]=i;
    70     lst[i]=st[top],st[++top]=i;
    71     }
    72     while (top) nxt[st[top--]]=n+1;
    73     for (RG ll i=1;i<=n;++i) suml[i]=suml[lst[i]]+(i-lst[i])*a[i];
    74     for (RG ll i=n;i;--i) sumr[i]=sumr[nxt[i]]+(nxt[i]-i)*a[i];
    75     for (RG ll i=1;i<=Q;++i) q[i].i=i,q[i].l=gi(),q[i].r=gi();
    76     buildST(),sort(q+1,q+Q+1,cmp),L=1,R=0,Ans=0;
    77     for (RG ll i=1;i<=Q;++i){
    78     while (L>q[i].l) L--,updatel(L,R,1);
    79     while (R<q[i].r) R++,updater(L,R,1);
    80     while (L<q[i].l) updatel(L,R,-1),L++;
    81     while (R>q[i].r) updater(L,R,-1),R--;
    82     ans[q[i].i]=Ans;
    83     }
    84     for (RG ll i=1;i<=Q;++i) printf("%lld
    ",ans[i]); return;
    85 }
    86 
    87 int main(){
    88     File("sequence");
    89     work();
    90     return 0;
    91 }
  • 相关阅读:
    我不会用 Triton 系列:Model Warmup 的使用
    我不会用 Triton 系列:Python Backend 的使用
    C++11 Memory Order
    我不会用 Triton 系列:Triton 搭建 ensemble 过程记录
    我不会用 Triton 系列:Stateful Model 学习笔记
    CUDA 概念汇总
    字符串的扩展
    梦学谷会员管理系统
    普希金-假如生活欺骗了你
    变量的解构赋值
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6656141.html
Copyright © 2020-2023  润新知