码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ4540][HNOI2016]序列

时间:2018-02-21 23:01:56      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:问题   algorithm   关系   using   include   opera   序列   ++i   bool   

BZOJ
Luogu

sol

区间?可离线?顺手就掏出了莫队。
最主要的问题就是移动区间怎么做到\(O(1)\)更新答案。
我们考虑由\([L+1,R]\)移动到\([L,R]\)
这样一共新产生了\(R-L+1\)个子区间\([L,L],[L,L+1]...[L,R]\)
\([L,R]\)中最小值的位置为\(P\),那么上述区间中\([L,P]...[L,R]\)的贡献就全都是\(a[P]\)
考虑用\(sr[i]\)表示左端点是\(i\),右端点在\(i\)\(n\)之间的所有区间的最小值之和。
那么上述中剩余的区间\([L,L]...[L,P-1]\)的贡献就应为\(sr[L]-sr[P]\)
处理\(sr\)数组:\(sr[i]=sr[nxt[i]]+(nxt[i]-i)*a[i]\)其中\(nxt[i]\)表示\(i\)之后第一个比\(a[i]\)小的数的位置。
同理处理左边的\(sl\)数组。
复杂度\(O(n\sqrt{n}+m\sqrt{n})\)

加一个莫队的注意事项:关于
while(R<q[i].r)while(L>q[i].l)while(R>q[i].r)以及while(L<q[i].l)的顺序关系。
最优的顺序就是像上面一样:右端点扩张->左端点扩张->右端点收缩->左端点收缩。不正确的处理顺序会导致左端点的位置在右端点的右边这种从而RE。

code

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e5+5;
int n,m,block,a[N],lg[N],ST[20][N],lst[N],nxt[N],Stack[N];
ll sl[N],sr[N],Ans,ans[N];
struct query{
    int l,r,id;
    bool operator < (const query b) const
        {return l/block<b.l/block||(l/block==b.l/block&&r<b.r);}
}q[N];
int Query(int l,int r)
{
    int k=lg[r-l+1];
    return a[ST[k][l]]<=a[ST[k][r-(1<<k)+1]]?ST[k][l]:ST[k][r-(1<<k)+1];
}
int main()
{
    n=gi();block=sqrt(n);m=gi();lg[0]=-1;
    for (int i=1;i<=n;++i) a[i]=gi(),ST[0][i]=i,lg[i]=lg[i>>1]+1;
    for (int j=1;j<20;++j)
        for (int i=1;i+(1<<j-1)<=n;++i)
            ST[j][i]=a[ST[j-1][i]]<=a[ST[j-1][i+(1<<j-1)]]?ST[j-1][i]:ST[j-1][i+(1<<j-1)];
    for (int i=1,top=0;i<=n;++i)
    {
        while (top&&a[Stack[top]]>=a[i]) --top;
        lst[i]=Stack[top];sl[i]=sl[lst[i]]+1ll*(i-lst[i])*a[i];
        Stack[++top]=i;
    }
    Stack[0]=n+1;
    for (int i=n,top=0;i;--i)
    {
        while (top&&a[Stack[top]]>=a[i]) --top;
        nxt[i]=Stack[top];sr[i]=sr[nxt[i]]+1ll*(nxt[i]-i)*a[i];
        Stack[++top]=i;
    }
    for (int i=1;i<=m;++i) q[i]=(query){gi(),gi(),i};
    sort(q+1,q+m+1);
    int L=1,R=0;
    for (int i=1,pos;i<=m;++i)
    {
        while (R<q[i].r)
        {
            ++R;pos=Query(L,R);
            Ans+=1ll*(pos-L+1)*a[pos]+sl[R]-sl[pos];
        }
        while (L>q[i].l)
        {
            --L;pos=Query(L,R);
            Ans+=1ll*(R-pos+1)*a[pos]+sr[L]-sr[pos];
        }
        while (R>q[i].r)
        {
            pos=Query(L,R);
            Ans-=1ll*(pos-L+1)*a[pos]+sl[R]-sl[pos];--R;
        }
        while (L<q[i].l)
        {
            pos=Query(L,R);
            Ans-=1ll*(R-pos+1)*a[pos]+sr[L]-sr[pos];++L;
        }
        ans[q[i].id]=Ans;
    }
    for (int i=1;i<=m;++i) printf("%lld\n",ans[i]);
    return 0;
}

[BZOJ4540][HNOI2016]序列

标签:问题   algorithm   关系   using   include   opera   序列   ++i   bool   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8457654.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!