[HNOI2016]序列(莫队,RMQ)

[HNOI2016]序列(莫队,RMQ)

洛谷  bzoj

一眼看不出来怎么用数据结构维护

然后还没修改

所以考虑莫队

以$(l,r-1) -> (l,r)$为例

对答案的贡献是$\Sigma_{i=l}^{r}minval(a[i:r])$

考虑维护前缀和

先用单调栈扫出$w[i]$作为最小值的左边界右边界$l_i,r_i$

然后回到上面的例子贡献就是$frontsum_{r}-frontsum_{rmqmin(l,r)}+w[rmqmin(l,r)]*(rmqmin(l,r)-l+1)$

完结...等等我好像忘了点啥

$frontsum_{i}$指的是从i向前拓展的i个包含i的子区间的区间最小值的和,也是可以用单调栈求出来的

时间复杂度略

#include<cstdio>
#include<cmath>
#include<algorithm>
using std::sort;
typedef long long lint;
const int N=100011;
template<typename tp>void read(tp &kk){
    #define ak *
    tp phy=0,ioi=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')ioi=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){phy=phy*10+ch-'0';ch=getchar();}
    kk=phy ak ioi;
}
int n,m,bl[N];
lint w[N];
int bsize;

int lg[N];
int lgl[N][17];
void is()
{
    for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    for(int i=1;i<=n;i++) lgl[i][0]=i;
    for(int k=1;k<=lg[n];k++)
    {
        for(int i=1;i-1+(1<<k)<=n;i++)
        {
            lgl[i][k]=w[lgl[i][k-1]]<w[lgl[i+(1<<(k-1))][k-1]]?lgl[i][k-1]:lgl[i+(1<<(k-1))][k-1];
        }
    }
}
int rmq(int l,int r){
    return w[lgl[l][lg[r-l+1]]]<
    w[lgl[r-(1<<lg[r-l+1])+1][lg[r-l+1]]]?
    lgl[l][lg[r-l+1]]:
    lgl[r-(1<<lg[r-l+1])+1][lg[r-l+1]];
}

int li[N],ri[N];
int st[N],hop;
void rkk()
{
    for(int i=1;i<=n;i++)
    {
        while(hop&&w[st[hop]]>w[i])
            ri[st[hop]]=i-1,hop--;
        st[++hop]=i;
        if(i==n)
            while(hop) ri[st[hop]]=i,hop--;
    }
    for(int i=n;i;i--)
    {
        while(hop&&w[st[hop]]>w[i])
            li[st[hop]]=i+1,hop--;
        st[++hop]=i;
        if(i==1)
            while(hop) li[st[hop]]=i,hop--;
    }
}
lint fsum[N],bsum[N];
void baka()
{
    for(int i=1;i<=n;i++)
        fsum[i]=fsum[li[i]-1]+w[i]*(i-li[i]+1);
    for(int i=n;i;i--)
        bsum[i]=bsum[ri[i]+1]+w[i]*(ri[i]-i+1);
}

struct ques
{
    int l,r,id;
    bool friend operator < (ques a,ques b)
    {
        if(bl[a.l]!=bl[b.l]) return bl[a.l]<bl[b.l];
        return bl[a.r]<bl[b.r];
    }
}q[N];

lint prt[N],tmp;

int main()
{
    read(n),read(m),bsize=ceil(sqrt(n));
    for(int i=1;i<=n;i++) read(w[i]),bl[i]=(i-1)/bsize+1;
    rkk();
    is();
    baka();
    for(int i=1;i<=m;i++) read(q[i].l),read(q[i].r),q[i].id=i;
    sort(q+1,q+1+m);
    int l=1,r=1;tmp=w[1];
    for(int i=1;i<=m;i++)
    {
        while(r<q[i].r){r++;tmp+=fsum[r]-fsum[rmq(l,r)]+((rmq(l,r)-l+1)*w[rmq(l,r)]);}
        while(l>q[i].l){l--;tmp+=bsum[l]-bsum[rmq(l,r)]+((r-rmq(l,r)+1)*w[rmq(l,r)]);}
        while(r>q[i].r){tmp-=fsum[r]-fsum[rmq(l,r)]+((rmq(l,r)-l+1)*w[rmq(l,r)]);r--;}
        while(l<q[i].l){tmp-=bsum[l]-bsum[rmq(l,r)]+((r-rmq(l,r)+1)*w[rmq(l,r)]);l++;}
        prt[q[i].id]=tmp;
    }
    for(int i=1;i<=m;i++) printf("%lld\n",prt[i]);
    return 0;
}
posted @ 2019-07-22 21:25  RikukiIX  阅读(183)  评论(0编辑  收藏  举报