超级钢琴 && ST表复习笔记

ST表

好久没写了, 所以写篇博客来回忆一下

用于解决RMQ问题

主要运用倍增的思想

具体做法:

1. 设f[i][j]为 $ [i,i+2^j] $ 区间内的极值, 然后预处理

2. 查询时: 设查询区间长度为len,返回左端点为起点长度为$ 2^{log_2(len)} $ 与右端点为终点同等长度的二者中的极值

(此处log需要下取整)

void prepare()
{
    lg[0]=-1;
    for(re int i=1;i<=n;++i) lg[i]=lg[i/2]+1;
    for(re int i=1;i<=lg[n];++i)
        for(re int j=1;j<=n;++j)
            f[j][i]=MAX(f[j][i-1], f[j+(1<<i-1)][i-1]);
}
int query(int l,int r)
{
    int LOG=lg[r-l+1];
    return MAX(f[l][LOG],f[r-(1<<LOG)+1][LOG]);
}

NOI2010 超级钢琴

题意简述:
对于一个长为n的序列求k段不同的长度在[L,R]中的区间, 使得选中的序列和的总和最大
n,m<=500000

Sol

常用小技巧: 碰到区间权值问题,可以考虑前缀和,转化为点权,然后运用数据结构即可

此题也是如此, 先转化为对于每个点,考虑其作为起点,则需要在之后[L,R]的区间中找到最大值
将所有最大值放入堆中,每弹出一次,就将该区间拆开

code

#include<bits/stdc++.h>
using namespace std;
#define re register
#define in inline
#define get getchar()
#define ll long long
in int read()
{
    int t=0, x=1; char ch=get;
    while(ch!='-' && (ch<'0' || ch>'9') ) ch=get;
    if(ch=='-') ch=get, x=-1;
    while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
    return t*x;
}
const int _=1e6+23;
const int LG=22;
int f[_][LG],n,k,L,R,a[_],lg[_];
in int MAX(int x,int y){ return a[x]>a[y] ? x : y;}
in int query(int l,int r)
{
    int LOG=lg[r-l+1];
    return MAX(f[l][LOG],f[r-(1<<LOG)+1][LOG]);
}
struct yzx{
    int l,r,num;
    int val(){ return a[query(l,r)] - a[num-1];}
}; //表示每个可能最大值区间右端点范围[l,r],以及左端点编号num
yzx YZX(int a,int b,int c){return yzx{a,b,c}; }
bool operator < (yzx x,yzx y){ return x.val() < y.val(); }
priority_queue<yzx> q;
int main()
{
    n=read(), k=read(), L=read(), R=read();
    lg[0]=-1;
    for(re int i=1;i<=n;++i) a[i]=read()+a[i-1], f[i][0]=i, lg[i]=lg[i/2]+1;
    for(re int i=1;i<=lg[n];++i)
        for(re int j=1;j<=n;++j)
            f[j][i]=MAX(f[j][i-1], f[j+(1<<i-1)][i-1]);
    for(re int i=1;i<=n;++i) {
        int st=i+L-1;
        if(st>n) break;
        q.push(YZX(st,min(n,st+(R-L)),i));
    }
    ll ans=0;
    while(k--)
    {
        yzx u=q.top(); q.pop();
        ans+=u.val();
        int pos=query(u.l,u.r);
        if(pos>u.l) q.push(YZX(u.l,pos-1,u.num));
        if(pos<u.r) q.push(YZX(pos+1,u.r,u.num));
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2021-05-18 22:16  yzhx  阅读(80)  评论(0编辑  收藏  举报