bzoj 2006 超级钢琴 —— ST表

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

本来应该是可以用主席树,找区间最小值,取出来后再找那段区间的次小值......

但也可以只找最小值,取出来后把原来区间分裂成两个,继续找最小值,用ST表即可;

发现自己还没写过 ST 表囧...

思路同这里:https://www.cnblogs.com/CQzhangyu/p/7071394.html

自己写了半天,才10分...奋力改了改,那个 find 里面 r++ 而 l 不 ++ 的细节真奇妙...

然后就50分了...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=5e5+5,inf=0x3f3f3f3f;
int n,k,L,R,t[xn],lg[xn],f[xn][25],id[xn][25],bin[25],ans;
struct N{
    int a,b,l,r;
    bool operator < (const N &y) const
        {return t[b]-t[a]<t[y.b]-t[y.a];}
};
priority_queue<N>q;
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return f?ret:-ret;
}
void find(int l,int r,int &y)
{
    int g=lg[r-l+1];//
    r++;//!!!!!
//    printf("id[%d][%d]=%d\n",l,g,id[l][g]);
    if(t[id[r][g]]<t[id[l+bin[g]][g]])y=id[r][g];
    else y=id[l+bin[g]][g];
//    printf("find(%d,%d)=%d\n",l,r,y);
}
int main()
{
    n=rd(); k=rd(); L=rd(); R=rd();
    bin[0]=1; 
    for(int i=1,x;i<=n;i++)x=rd(),t[i]=t[i-1]+x;
    for(int i=1,p,lst=1;i<=n;i++)
    {
        if(i<lst*2)lg[i]=lg[i-1];
        else lg[i]=lg[i-1]+1,lst*=2,bin[lg[i]]=lst;
        
        id[i][0]=i-1; f[i][0]=i-1;
        for(int j=1;j<=20;j++)
        {
            f[i][j]=f[f[i][j-1]][j-1];
            if(t[id[i][j-1]]<t[id[f[i][j-1]][j-1]])id[i][j]=id[i][j-1];
            else id[i][j]=id[f[i][j-1]][j-1];
        }
        
        int l=max(i-R,0),r=i-L,len=r-l+1;
        if(l>r)continue;
        find(l,r,p); q.push((N){p,i,l,r});
//        printf("ps:%d,%d\n",p,i);
    }
    int cnt=0,p;
    while(cnt<k)
    {
        int a=q.top().a,b=q.top().b,l=q.top().l,r=q.top().r; q.pop();
        if(l<=a-1)find(l,a-1,p),q.push((N){p,b,l,a-1})/*,printf("ps:%d,%d\n",p,b)*/;
        if(a+1<=r)find(a+1,r,p),q.push((N){p,b,a+1,r})/*,printf("ps:%d,%d\n",p,b)*/;
        cnt++; ans+=t[b]-t[a];
//        printf("a=%d b=%d\n",a,b);
    }
    printf("%d\n",ans);
    return 0;
}

最后发现把 ans 改成 long long 就A了!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=5e5+5,inf=0x3f3f3f3f;
int n,k,L,R,t[xn],lg[xn],f[xn][25],id[xn][25],bin[25];
long long ans;
struct N{
    int a,b,l,r;
    bool operator < (const N &y) const
        {return t[b]-t[a]<t[y.b]-t[y.a];}
};
priority_queue<N>q;
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return f?ret:-ret;
}
void find(int l,int r,int &y)
{
    int g=lg[r-l+1];//
    r++;//!!!!!
//    printf("id[%d][%d]=%d\n",l,g,id[l][g]);
    if(t[id[r][g]]<t[id[l+bin[g]][g]])y=id[r][g];
    else y=id[l+bin[g]][g];
//    printf("find(%d,%d)=%d\n",l,r,y);
}
int main()
{
    n=rd(); k=rd(); L=rd(); R=rd();
    bin[0]=1; 
    for(int i=1,x;i<=n;i++)x=rd(),t[i]=t[i-1]+x;
    for(int i=1,p,lst=1;i<=n;i++)
    {
        if(i<lst*2)lg[i]=lg[i-1];
        else lg[i]=lg[i-1]+1,lst*=2,bin[lg[i]]=lst;
        
        id[i][0]=i-1; f[i][0]=i-1;
        for(int j=1;j<=20;j++)
        {
            f[i][j]=f[f[i][j-1]][j-1];
            if(t[id[i][j-1]]<t[id[f[i][j-1]][j-1]])id[i][j]=id[i][j-1];
            else id[i][j]=id[f[i][j-1]][j-1];
        }
        
        int l=max(i-R,0),r=i-L,len=r-l+1;
        if(l>r)continue;
        find(l,r,p); q.push((N){p,i,l,r});
//        printf("ps:%d,%d\n",p,i);
    }
    int cnt=0,p;
    while(cnt<k)
    {
        int a=q.top().a,b=q.top().b,l=q.top().l,r=q.top().r; q.pop();
        if(l<=a-1)find(l,a-1,p),q.push((N){p,b,l,a-1})/*,printf("ps:%d,%d\n",p,b)*/;
        if(a+1<=r)find(a+1,r,p),q.push((N){p,b,a+1,r})/*,printf("ps:%d,%d\n",p,b)*/;
        cnt++; ans+=t[b]-t[a];
//        printf("a=%d b=%d\n",a,b);
    }
    printf("%lld\n",ans);
    return 0;
}
A

但已经模仿了TJ啦...处理的时候果然要带上自己,不然各种不方便...

别忘了开 long long !因为是多段区间的和!

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=5e5+5,inf=0x3f3f3f3f;
int n,k,L,R,t[xn],lg[xn],id[xn][25];
long long ans;
struct N{
    int a,b,l,r;
    bool operator < (const N &y) const
        {return t[b]-t[a]<t[y.b]-t[y.a];}
};
priority_queue<N>q;
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return f?ret:-ret;
}
int mn(int a,int b){return t[a]<t[b]?a:b;}
int find(int l,int r)
{
    if(l>r)return -1;
    int g=lg[r-l+1];
    return mn(id[l][g],id[r-(1<<g)+1][g]);
}
int main()
{
    n=rd(); k=rd(); L=rd(); R=rd();
    for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
    for(int i=1,x;i<=n;i++)x=rd(),t[i]=t[i-1]+x,id[i][0]=i;//
    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)-1<=n;i++)//0  //-1
            id[i][j]=mn(id[i][j-1],id[i+(1<<(j-1))][j-1]);
    for(int i=L;i<=n;i++)q.push((N){find(max(i-R,0),i-L),i,max(i-R,0),i-L});
    int cnt=0,p;
    while(cnt<k)
    {
        int a=q.top().a,b=q.top().b,l=q.top().l,r=q.top().r; q.pop();
        cnt++; ans+=t[b]-t[a];
        int c=find(l,a-1),d=find(a+1,r);
        if(c!=-1)q.push((N){c,b,l,a-1});
        if(d!=-1)q.push((N){d,b,a+1,r});
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-09-30 07:49  Zinn  阅读(179)  评论(0编辑  收藏  举报