题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2006

题意: 给出一个数列A,L,R,构造出一个新的集合,集合中的数字为A中任意连续t(L<=t<=R)个数字的和(集合中的数字可以重复)。求集合中前K大的数字和。

思路:首先,我们令S[i]表示A的前i项和,P[i] 表示以A中第i个数字结尾可以取到的最大值,那么显然有:

求出P之后,我们可以用一个堆或者优先队列来维护最大值。那么现在来了另外一个问题,某次在优先队列中取得的是P[i],那么显然要将其从优先队列中删除,此时,以i结尾的次大值也是有可能成为最后答案中一部分的,类似的,我们可能还要求第三大、第四大,也就是求一段区间的第三小、第四小等,我们可以用划分树解决这个问题。现在,整个问题都解决了,首先,求出S,将S建立划分树。然后将所有P插入优先队列。每次从优先队列中取出最大值,删掉,并将这个最大值对应的原数列中位置结尾的下一大的值插入优先队列(这一步也就是在划分树中找到下一小的值),直到取出K个。

int n,m,L,R;
i64 b[N],s[N],S[N];

struct node
{
    int L,R;
};

node a[N<<2];
i64 t[35][N];
int tot[35][N];

void init()
{
    RD(n,m); RD(L,R);
    int i;
    for(i=2;i<=n+1;i++) RD(b[i]),S[i]=t[1][i]=s[i]=s[i-1]+b[i];
    n++;
    sort(s+1,s+n+1);
}

void build(int dep,int u,int L,int R)
{
    a[u].L=L;
    a[u].R=R;
    if(L==R) return;
    int mid=(L+R)>>1;
    int i,sameNum=mid-L+1;
    FOR(i,L,R) if(t[dep][i]<s[mid]) sameNum--;
    int LL=L,LR=mid,RL=mid+1,RR=R;
    int Lnum=0,Rnum=0;
    i64 x;
    FOR(i,L,R)
    {
        if(i==L) tot[dep][i]=0;
        else tot[dep][i]=tot[dep][i-1];
        x=t[dep][i];
        if(x<s[mid])
        {
            tot[dep][i]++;
            t[dep+1][LL+Lnum]=x;
            Lnum++;
        }
        else if(x>s[mid])
        {
            t[dep+1][RL+Rnum]=x;
            Rnum++;
        }
        else
        {
            if(sameNum>0)
            {
                sameNum--;
                tot[dep][i]++;
                t[dep+1][LL+Lnum]=x;
                Lnum++;
            }
            else
            {
                t[dep+1][RL+Rnum]=x;
                Rnum++;
            }
        }
    }
    build(dep+1,u*2,LL,LR);
    build(dep+1,u*2+1,RL,RR);
}

i64 query(int dep,int u,int L,int R,int K)
{
    if(L==R) return t[dep][L];
    int x,y,xx,yy,_L,_R;
    int mid=(a[u].L+a[u].R)>>1;
    if(L==a[u].L) x=0;
    else x=tot[dep][L-1];
    y=tot[dep][R]-x;
    if(y>=K)
    {
        _L=a[u].L+x;
        _R=a[u].L+x+y-1;
        return query(dep+1,u*2,_L,_R,K);
    }
    else
    {
        xx=L-a[u].L-x;
        yy=R-L+1-y;
        _L=mid+1+xx;
        _R=mid+1+xx+yy-1;
        return query(dep+1,u*2+1,_L,_R,K-y);
    }
}

struct Node
{
    int pos,k;
    i64 x;

Node(){}
    Node(int _pos,int _k,i64 _x)
    {
        pos=_pos;
        k=_k;
        x=_x;
    }
    
    int operator<(const Node &a) const
    {
        return x<a.x;
    }
};

priority_queue<Node> Q;

int main()
{
    init(); build(1,1,1,n);
    int i,x,y;
    for(i=L+1;i<=n;i++)
    {
        x=max(1,i-R);
        y=i-L;
        Q.push(Node(i,1,S[i]-query(1,1,x,y,1)));
    }
    i64 ans=0;
    Node p;
    while(m--)
    {
        p=Q.top(); Q.pop();
        ans+=p.x;
        x=max(1,p.pos-R);
        y=p.pos-L;
        if(p.k+1>y-x+1) continue;
        Q.push(Node(p.pos,p.k+1,S[p.pos]-query(1,1,x,y,p.k+1)));
    }
    PR(ans);
}

BZOJ 2006 超级钢琴(划分树+优先队列)的更多相关文章

  1. BZOJ 2006 NOI2010 超级钢琴 划分树+堆

    题目大意:给定一个序列.找到k个长度在[l,r]之间的序列.使得和最大 暴力O(n^2logn),肯定过不去 看到这题的第一眼我OTZ了一下午... 后来研究了非常久别人的题解才弄明确怎么回事...蒟 ...

  2. bzoj2006 noi2010 超级钢琴 主席树 + 优先队列

    Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2435  Solved: 1195 Description 小 Z是一个小有名气的钢琴家,最近C博士送 ...

  3. BZOJ 2006 超级钢琴(堆+主席树)

    很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...

  4. [BZOJ 2006] 超级钢琴

    Link: https://www.lydsy.com/JudgeOnline/problem.php?id=2006 Algorithm: 对于此类区间最值类问题,我们可以通过控制一端不变来寻找当前 ...

  5. bzoj 2006 超级钢琴 —— ST表

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006 本来应该是可以用主席树,找区间最小值,取出来后再找那段区间的次小值...... 但也可 ...

  6. 【BZOJ 2006】2006: [NOI2010]超级钢琴(RMQ+优先队列)

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2792  Solved: 1388 Description 小 ...

  7. [BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 3591  Solved: 1780[Submit][Statu ...

  8. [NOI2010]超级钢琴 主席树

    [NOI2010]超级钢琴 链接 luogu 思路 和12省联考的异或粽子一样. 堆维护n个左端点,每次取出来再放回去次 代码 #include <bits/stdc++.h> #defi ...

  9. [NOI2010][bzoj2006] 超级钢琴 [主席树/ST表+堆]

    题面: 传送门 思路: 首先容易想到用堆维护的O(n2logn)暴力 那么肯定就是在这个基础上套数据结构了[愉快] 然而我因为过于蒟蒻......只想得到主席树暴力***过去的方法 大概就是把前缀和算 ...

随机推荐

  1. bzoj 2751 快速幂

    首先我们知道,对于所有种情况,我们可以将每一位可以放的 数的值加起来,所有位置的乘起来,等于的就是最后的答案,具体 为什么正确,可以根据乘法分配律来想一想. 那么对于所有不做要求的,快速幂直接算就行了 ...

  2. Orchard 候补神器说明

    Orchard学习视频已登录百度传课: http://www.chuanke.com/3027295-124882.html 获取Orchard候补神器请加qq群432158140  ! 候补神器是一 ...

  3. XSS的原理分析与解剖(二)

    0×01 前言:  上节(http://www.freebuf.com/articles/web/40520.html)已经说明了xss的原理及不同环境的构造方法.本期来说说XSS的分类及挖掘方法. ...

  4. HDOJ 2082 找单词 (母函数)

    找单词 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  5. Extjs中自定义事件

    //Ext中所谓的响应事件,响应的主要是组件中已经定义的事件(通过看api各组件的events可以找到)         //主要作用就是利用on调用各组件的事件处理函数,然后在函数中作用户想要的操作 ...

  6. 真机模拟器.a文件编译报错

  7. java 分割split

    1.如果用“.”作为分隔的话,必须是如下写法:String.split("\\."),这样才能正确的分隔开,不能用String.split(".");2.如果用 ...

  8. CodeIgniter 错误: In order to use the Session class you are required to set an encryption key

    CodeIgniter SESSION  第一次用 session 遇到这个错误 , 说是要加一个密钥才可以使用,加就加吧, 打开 config.php 找到以下代码 /*|------------- ...

  9. 关于SQL查询效率,100w数据,查询只要1秒

    1.关于SQL查询效率,100w数据,查询只要1秒,与您分享:机器情况p4: 2.4内存: 1 Gos: windows 2003数据库: ms sql server 2000目的: 查询性能测试,比 ...

  10. poj 1568 Find the Winning Move 极大极小搜索

    思路:用极大极小搜索解决这样的问题很方便!! 代码如下: #include <cstdio> #include <algorithm> #define inf 10000000 ...