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;
    }
    未经许可,禁止搬运。
  • 相关阅读:
    PHP观察者模式 (转)
    PHP单例模式 (转)
    PHP解决并发问题的几种实现(转)
    php结合redis实现高并发下的抢购、秒杀功能 (转)
    使用 redis 减少 秒杀库存 超卖思路 (转)
    mysql视图学习总结(转)
    mysql 存储过程
    PHP中的魔术方法和关键字
    bzoj3462DZY Loves Math II
    bzoj1453[Wc]Dface双面棋盘
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9670154.html
Copyright © 2011-2022 走看看