bzoj 2006 [NOI2010]超级钢琴——ST表+堆

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006

每个右端点的左端点在一个区间内;用堆记录端点位置、可选区间,按价值排序;拿出一个后也许分裂成两个。

第一次写了ST表,写得巨复杂,记录向前/后的最小值和位置,还为了预处理,又记 2^j 走到哪;调了半天边界,最后发现是Lg写错了!至今仍不知那样写为什么会错……

看看别人的代码,原来不用记两个方向的,用的时候往前跳几步再用向后的就行!也不用记录最小值,只要记录位置就行了;也不用记录 to[ ][ ] ,只要从 i+2^j 有没有超过n就能判断边界。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int N=5e5+5,Lm=20;
int n,m,L,R,a[N],s[N],Lg[N],stp[N][Lm+5],stn[N][Lm+5],to[N][Lm+5];
int idp[N][Lm+5],idn[N][Lm+5];
ll ans;
struct Node{
    int ps,to,l,r,v;
    Node(int p,int t,int l,int r,int v):ps(p),to(t),l(l),r(r),v(v) {}
    bool operator< (const Node &b) const
        {return v<b.v;}
};
priority_queue<Node> q;
int rdn()
{
    int ret=0;bool fx=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
    while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return fx?ret:-ret;
}
void init()
{
    /*
    int i=1,cd=0,nxt;
    for(;i<=n;i=nxt,cd++)
    {
        nxt=i<<1;
        for(int j=i;j<nxt&&j<=n;j++) Lg[j]=cd;
    }
    i>>=1;
    for(;i<=n;i++) Lg[i]=cd;
    */
    for(int i=2;i<=n;i++) Lg[i]=Lg[i>>1]+1;

    memset(to,0x3f,sizeof to);//
    for(int i=0;i<n;i++)
    {
        stp[i][0]=s[i]; idp[i][0]=i;
        to[i][0]=i-1;
        for(int j=1,d;j<=Lm;j++)
        {
            d=to[i][j-1];
            if(d<0||to[d][j-1]>n)break;// >n!!! //if d<0
            to[i][j]=to[d][j-1];
            if(stp[d][j-1]<stp[i][j-1])
            {
                stp[i][j]=stp[d][j-1]; idp[i][j]=idp[d][j-1];
            }
            else
            {
                stp[i][j]=stp[i][j-1]; idp[i][j]=idp[i][j-1];
            }
        }
    }
    memset(to,0x3f,sizeof to);
    for(int i=n-1;i>=0;i--)
    {
        stn[i][0]=s[i]; idn[i][0]=i;
        to[i][0]=i+1;
        for(int j=1,d;j<=Lm;j++)
        {
            d=to[i][j-1];
            if(to[d][j-1]>n)break;
            to[i][j]=to[d][j-1];
            if(stn[d][j-1]<stn[i][j-1])
            {
                stn[i][j]=stn[d][j-1]; idn[i][j]=idn[d][j-1];
            }
            else
            {
                stn[i][j]=stn[i][j-1]; idn[i][j]=idn[i][j-1];
            }
        }
    }
}
int main()
{
    n=rdn(); m=rdn(); L=rdn(); R=rdn();
    for(int i=1;i<=n;i++) a[i]=rdn(),s[i]=s[i-1]+a[i];
    init();
    for(int i=1,d,t;i<=n;i++)
    {
        int l=i-R,r=i-L;//not +1
        if(r<0) continue; l=max(l,0);
        t=Lg[r-l+1];//not +1
        d=(stp[r][t]<stn[l][t]?idp[r][t]:idn[l][t]);
        q.push(Node(i,d,l,r,s[i]-s[d]));
    }

    while(m--)
    {
        Node k=q.top(); q.pop(); ans+=k.v;
        int l1=k.l,r1=k.to-1, l2=k.to+1,r2=k.r;
        int t,d;
        if(l1<=r1)
        {
            t=Lg[r1-l1+1];
            d=(stp[r1][t]<stn[l1][t]?idp[r1][t]:idn[l1][t]);
            q.push(Node(k.ps,d,l1,r1,s[k.ps]-s[d]));
        }

        if(l2<=r2)
        {
            t=Lg[r2-l2+1];
            d=(stp[r2][t]<stn[l2][t]?idp[r2][t]:idn[l2][t]);
            q.push(Node(k.ps,d,l2,r2,s[k.ps]-s[d]));
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted on 2018-09-30 07:59  Narh  阅读(106)  评论(0编辑  收藏  举报

导航