zoukankan      html  css  js  c++  java
  • [bzoj4540][Hnoi2016]序列

    来自FallDream的博客,未经允许,请勿转载,谢谢合作。


    给定长度为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。

    n,q<=10^5

    是子串偏说子序列...

    其实就是个矩形加  矩形查  可以用扫描线+线段树nlogn实现,但是中间量会爆longlong..........直接自然溢出就行了

    写了个莫队  考虑插入右端点时答案改变的量,只需要计算子串右端点为现在右端点的答案即可 

    找到[L,R]中的最小值位置pos,那么左端点在[L,pos]时候贡献是a[pos]

    用单调栈求出每个数字前面第一个比他小的数字位置,做一个简单递推 f[i]=f[last[i]]+(i-last[i])*a[i] 脑补一下应该比较好理解。

    这样[pos,R]的贡献直接相减即可。

    删除/左端点移动 同理

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define ll long long 
    #define MN 100000
    #define MD 17
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    ll Rt[MN+5],Lt[MN+5],Ans[MN+5],ans=0;
    int n,m,a[MN+5],block[MN+5],size,la[MN+5],L,R,ne[MN+5],Q[MN+5],top=0,f[MD+1][MN*3+5],Log[MN+5];
    struct ques{int l,r,id;}q[MN+5];
    bool cmp(ques x,ques y){return block[x.l]==block[y.l]?x.r<y.r:x.l<y.l;}
    inline int U(int x,int y){return a[x]>a[y]?y:x;}
    inline int Query(int l,int r){int s=Log[r-l+1];return U(f[s][l],f[s][r-(1<<s)+1]);}
    
    void AddR(int x,int ad)
    {
        int p=Query(L,R);
        ans+=1LL*ad*(Rt[x]-Rt[p]+1LL*(p-L+1)*a[p]);        
    }
    
    void AddL(int x,int ad)
    {
        int p=Query(L,R); 
        ans+=1LL*ad*(Lt[x]-Lt[p]+1LL*(R-p+1)*a[p]);
    }
    
    int main()
    {
        n=read();m=read();size=sqrt(n);a[0]=2e9;
        for(int i=1;i<=n;++i) a[i]=read(),block[i]=(i-1)/size+1,f[0][i]=i;
        for(int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
        sort(q+1,q+m+1,cmp);Log[0]=-1;
        for(int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
        for(int i=1;i<=MD;++i)
            for(int j=1;j<=n;++j)
                f[i][j]=U(f[i-1][j],f[i-1][j+(1<<(i-1))]);
        for(int i=1;i<=n;++i)
        {
            while(top&&a[Q[top]]>a[i])    ne[Q[top]]=i,--top;
            la[i]=Q[top];Q[++top]=i;
        }
        for(int i=1;i<=top;++i) ne[Q[i]]=n+1;
        for(int i=1;i<=n;++i) Rt[i]=Rt[la[i]]+1LL*a[i]*(i-la[i]);
        for(int i=n;i;--i)    Lt[i]=Lt[ne[i]]+1LL*a[i]*(ne[i]-i);
        ans=a[L=R=1];
        for(int i=1;i<=m;++i)
        {
            while(R<q[i].r) ++R,AddR(R,1);    
            while(L>q[i].l) --L,AddL(L,1);
            while(R>q[i].r) AddR(R,-1),--R;
            while(L<q[i].l) AddL(L,-1),++L;
            Ans[q[i].id]=ans; 
        }
        for(int i=1;i<=m;++i) printf("%lld
    ",Ans[i]);
        return 0;
    }
  • 相关阅读:
    Python基础(2)
    Python基础(3)
    Python基础(1)
    [日本语]单词1
    【.Net】 C#参数数组与函数重载
    pyenv
    Pip批量安装/卸载包
    Xcode中模拟器慢
    iPhone的设备名转换
    在python命令行执行sudo命令
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4540.html
Copyright © 2011-2022 走看看