loj #2051. 「HNOI2016」序列(莫队+ST+单调栈)

来源:互联网 发布:windows loader 和kms 编辑:程序博客网 时间:2024/06/07 01:44

题目链接

#2051. 「HNOI2016」序列

l,r 所有子集最小值和

分析

又是区间查询,上莫队了.首先想[l,r]-> [l,r+1] 它的增量是多少.
设[l,r+1] 的最小值的位置是 p, 那么显然增加的贡献为 a[p](pl+1)+(r+1)

sl[i] 表示以 i 为右端点的所有区间的贡献前缀和,那么显然当前区间中 r+1 为右端点的贡献为sl[r+1]sl[p]

l[i] : 左边第一个比a[i] 严格小的位置
r[i] : 右边第一个小于等于a[i] 的位置

那么显然

sl[i]=sl[l[i]]+a[i](il[i])
因此用单调栈预处理 l[i],r[i],然后用ST表查询最小值的位置就好了

中途WA了很多次,原来莫队更新的顺序很重要,特别是与区间相关,点不独立的问题

AC code

#include <bits/stdc++.h>using namespace std;#define ms(x,v) (memset((x),(v),sizeof(x)))#define pb push_back#define mp make_pair#define fi first#define se secondtypedef long long LL;typedef pair<int,int > Pair;const int maxn = 1e5+10;int n,m;LL a[maxn];const int S = 300;struct Query{    int l,r,id;    bool operator < (const Query & o)const{        return l/S == o.l/S?r < o.r:l<o.l;    }};Query q[maxn];int l[maxn],r[maxn],stk[maxn],top;LL sl[maxn],sr[maxn],ret[maxn];void init() {    top=0;    for(int i=1 ; i<=n ; ++i){        while (top && a[stk[top]] >=a[i])r[stk[top--]] =i;//被右端第一个小于等于它的元素驱逐出栈        stk[++top] =i;    }    top=0;    for(int i=n ; i>0 ; --i){        while (top && a[stk[top]] > a[i])l[stk[top--]] = i;        stk[++top] = i;    }    sl[0] = 0;sr[n+1] = 0;l[1] =0;r[n] = n+1;    for(int i=1 ; i<=n ; ++i)sl[i] = sl[l[i]]+(LL)a[i]*(i-l[i]);    for(int i=n ; i>0 ; --i)sr[i] = sr[r[i]] + (LL)a[i]*(r[i]-i);}namespace ST{    int st[maxn][22],lg2[maxn];    void init_rmq(int n,LL a[]) {        lg2[0] =-1;        for(int i=1 ; i<=n ; ++i){            lg2[i] = ((i&(i-1)) == 0)?lg2[i-1]+1:lg2[i-1];            st[i][0] =i;        }        for(int j=1 ; j<=lg2[n]; ++j)            for(int i=1 ; i+(1<<j)-1 <=n ; ++i)                st[i][j] = (a[st[i][j-1]]<a[st[i+(1<<(j-1))][j-1]])?st[i][j-1]:st[i+(1<<(j-1))][j-1];    }    int rmq(int l,int r,LL a[]){        int k = lg2[r-l+1];        return a[st[l][k]] < a[st[r-(1<<k)+1][k]]?st[l][k]:st[r-(1<<k)+1][k];    }};using namespace ST;inline LL moveL(int l,int r) {    int p = rmq(l,r,a);    return sr[l]-sr[p]+a[p]*(r-p+1);}inline LL moveR(int l,int r){    int p = rmq(l,r,a);    return sl[r] - sl[p]+a[p]*(p-l+1);}int main(){    ios_base::sync_with_stdio(0);    cin.tie(0);    cout.tie(0);    cin>>n>>m;    for(int i=1 ; i<=n ; ++i)cin>>a[i];    init_rmq(n,a);    init();    for(int i=0 ; i<m ; ++i){        q[i].id = i;cin>>q[i].l >> q[i].r;    }    sort(q,q+m);    int curL=q[0].l,curR = q[0].l-1;    LL ans =0;    for(int i=0 ; i<m ; ++i){        int L = q[i].l,R = q[i].r;        while (curR < R)ans += moveR(curL,++curR);        while (curL > L)ans += moveL(--curL,curR);        while (curR > R)ans -= moveR(curL,curR--);        while (curL < L)ans -=moveL(curL++,curR);        ret[q[i].id] = ans;    }    for(int i=0 ; i<m ; ++i)std::cout << ret[i] << '\n';    return 0;}
原创粉丝点击