zoukankan      html  css  js  c++  java
  • [BZOJ] 2006: [NOI2010]超级钢琴

    题意:给一个序列,问长度为L~R的子串和中前k大的和

    对于O(n^2)的区间枚举,考虑枚举一个点,计算另一个点

    于是枚举左端点,计算出在范围内且使区间和最大的右端点(ST表完成)

    这时候的最大值一定是全局最大值,取出后考虑以该左端点为左端点的区间次大值,设原区间在右端点y处取到最大,则将y删去后的两个区间有可能取到次大值,加入堆即可

    复杂度O(nlogn)

    ST表的边界一定要注意!log2能手写就手写咯

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    
    using namespace std;
    
    inline int rd(){
      int ret=0,f=1;char c;
      while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
      while(isdigit(c))ret=ret*10+c-'0',c=getchar();
      return ret*f;
    }
    
    const int MAXN = 1000005;
    
    int n,m,L,R;
    int sum[MAXN],f[2*MAXN][33],g[2*MAXN][33];
    
    int lg2(int x){
      int ret=1;
      while((1<<ret)<x)ret++;
      return ret-1;
    }
    int query(int l,int r){
      if(l==r)return g[l][0];
      int len=lg2(r-l+1);
      return f[l][len]<f[r-(1<<len)+1][len]?g[r-(1<<len)+1][len]:g[l][len];
    }
    
    struct Node{
      int x,y,l,r;
      Node(int _x=0,int _l=0,int _r=0){
        x=_x;l=_l;r=_r;
        y=query(l,r);
        // cout<<"Push:"<<x<<" "<<y<<" "<<l<<" "<<r<<endl;
      }
      bool operator <(const Node &rhs)const{
        return sum[y]-sum[x-1]<sum[rhs.y]-sum[rhs.x-1];
      }
    }tmp;
    priority_queue<Node> Q;
    int main(){
      n=rd();m=rd();L=rd();R=rd();
      for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+rd();
        f[i][0]=sum[i];g[i][0]=i;
      }
      for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i<=n;i++){
          if(f[i][j-1]>f[i+(1<<(j-1))][j-1]){
            f[i][j]=f[i][j-1];
            g[i][j]=g[i][j-1];
          }else{
            f[i][j]=f[i+(1<<(j-1))][j-1];
            g[i][j]=g[i+(1<<(j-1))][j-1];
          }
        }
      }
      for(int i=1;i+L-1<=n;i++){
        int l=i+L-1,r=i+R-1;
        r=min(r,n);
        Q.push(Node(i,l,r));
      }
      long long ans=0;
      int cnt=0;
      int x,y,u,v;
      while(cnt<m){
        tmp=Q.top();Q.pop();
        x=tmp.x,y=tmp.y,u=tmp.l,v=tmp.r;
        // cout<<x<<" "<<y<<endl;
        ans+=sum[y]-sum[x-1];
        if(y-1>=u){Q.push(Node(x,u,y-1));}
        if(y+1<=v){Q.push(Node(x,y+1,v));}
        cnt++;
      }
      cout<<ans;
      return 0;
    }
    未经许可,禁止搬运。
  • 相关阅读:
    Java面向对象之内部类(匿名内部类)
    Java面向对象之内部类(访问格式)
    Java面向对象之USB接口实例
    Java面向对象之多态(成员访问特点) 入门实例
    Java面向对象之多态(向上、向下转型) 入门实例
    Java面向对象之接口interface 入门实例
    Ansible 的安装
    Windows server 2016安装Docker EE
    Docker-py 的使用
    flask 上传文件
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9670154.html
Copyright © 2011-2022 走看看