bzoj 4504: K个串大根堆+主席树

Posted lokiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4504: K个串大根堆+主席树相关的知识,希望对你有一定的参考价值。

像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(d,l,r,p,v)表示右端点为d,左端点区间为(l,r),最大区间和值为v左端点在p上
关于怎么快速求区间和,用可持久化线段树维护(主席树?)每个点到他root的区间和,这样每次右端点右移就是上一个的线段树在(la[a[i]]+1,i)加上a[i],la是这个值a[i]上一次出现的位置
然后就可以在线处理询问了
有一点因为这个线段树建的是1~n,所以右端点不是n的时候取max会取到右端点向右还是初始值0的位置(有可能前面是负数),这样的解决方法就是先全填成-inf,然后每次右移的时候先把右端点加上inf再处理区间加

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
const int N=300005;
int n,m,has,rt[N],tot,la[N];
long long a[N],g[N],rl[N],ans;
map<long long ,int>mp;
struct zxs
{
    int ls,rs,p;
    long long mx,lz;
}t[7000005];
struct qwe
{
    int d,l,r,p;
    long long v;
    qwe(int D=0,int L=0,int R=0,int P=0,long long V=0)
    {
        d=D,l=L,r=R,p=P,v=V;
    }
    bool operator < (const qwe &a) const
    {
        return v<a.v;
    }
};
priority_queue<qwe>q;
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void build(int &ro,int l,int r)
{
    ro=++tot;
    t[ro].p=l,t[ro].mx=-1e15;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(t[ro].ls,l,mid);
    build(t[ro].rs,mid+1,r);
}
void ud(int ro)
{
    if(t[t[ro].ls].mx>t[t[ro].rs].mx)
        t[ro].mx=t[t[ro].ls].mx,t[ro].p=t[t[ro].ls].p;
    else
        t[ro].mx=t[t[ro].rs].mx,t[ro].p=t[t[ro].rs].p;
}
void update(int &ro,int la,int l,int r,int ll,int rr,long long v,long long lz)
{
    ro=++tot;
    t[ro]=t[la];
    t[ro].lz+=lz;
    t[ro].mx+=lz;
    if(l==ll&&r==rr)
    {
        t[ro].lz+=v;
        t[ro].mx+=v;
        return;
    }
    int mid=(l+r)>>1;
    if(t[ro].lz)
    {
        if(rr<=mid)
        {
            t[ro].rs=++tot;
            t[t[ro].rs]=t[t[la].rs];
            t[t[ro].rs].mx+=t[ro].lz;
            t[t[ro].rs].lz+=t[ro].lz;
            update(t[ro].ls,t[la].ls,l,mid,ll,rr,v,t[ro].lz);
        }
        else if(ll>mid)
        {
            t[ro].ls=++tot;
            t[t[ro].ls]=t[t[la].ls];
            t[t[ro].ls].mx+=t[ro].lz;
            t[t[ro].ls].lz+=t[ro].lz;
            update(t[ro].rs,t[la].rs,mid+1,r,ll,rr,v,t[ro].lz);
        }
        else
        {
            update(t[ro].ls,t[la].ls,l,mid,ll,mid,v,t[ro].lz);
            update(t[ro].rs,t[la].rs,mid+1,r,mid+1,rr,v,t[ro].lz);
        }
        t[ro].lz=0;
    }
    else
    {
        if(rr<=mid)
            update(t[ro].ls,t[la].ls,l,mid,ll,rr,v,0);
        else if(ll>mid)
            update(t[ro].rs,t[la].rs,mid+1,r,ll,rr,v,0);
        else
        {
            update(t[ro].ls,t[la].ls,l,mid,ll,mid,v,0);
            update(t[ro].rs,t[la].rs,mid+1,r,mid+1,rr,v,0);
        }
    }
    ud(ro);
}
pair<long long,int> ques(int ro,int l,int r,int ll,int rr)
{//cerr<<l<<" "<<r<<"   "<<ll<<" "<<rr<<endl;
    if(l==ll&&r==rr)
        return make_pair(t[ro].mx,t[ro].p);
    if(t[ro].lz)
    {
        t[tot+1]=t[t[ro].ls];
        t[tot+1].mx+=t[ro].lz;
        t[tot+1].lz+=t[ro].lz;
        t[ro].ls=tot+1;
        t[tot+2]=t[t[ro].rs];
        t[tot+2].mx+=t[ro].lz;
        t[tot+2].lz+=t[ro].lz;
        t[ro].rs=tot+2;
        tot+=2;
        t[ro].lz=0;
    }
    int mid=(l+r)>>1;
    if(rr<=mid)
        return ques(t[ro].ls,l,mid,ll,rr);
    else if(ll>mid)
        return ques(t[ro].rs,mid+1,r,ll,rr);
    else
    {
        pair<long long,int>a=ques(t[ro].ls,l,mid,ll,mid),b=ques(t[ro].rs,mid+1,r,mid+1,rr);
        return (a.first>b.first)?a:b;
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i]=g[i]=read();
    sort(g+1,g+1+n);
    for(int i=1;i<=n;i++)
        if(i==1||g[i]!=g[i-1])
            mp[g[i]]=++has,rl[has]=g[i];
    build(rt[0],1,n);
    for(int i=1;i<=n;i++)
    {
        update(rt[i],rt[i-1],1,n,i,i,1e15,0);
        update(rt[i],rt[i],1,n,la[mp[a[i]]]+1,i,a[i],0);
        la[mp[a[i]]]=i;//cerr<<"OK"<<endl;
    }
    for(int i=1;i<=n;i++)
        q.push(qwe(i,1,i,t[rt[i]].p,t[rt[i]].mx));
    while(m--)
    {
        qwe u=q.top();
        q.pop();
        ans=u.v;//cerr<<ans<<endl;
        if(u.l<=u.p-1)
        {
            pair<long long,int>nw=ques(rt[u.d],1,n,u.l,u.p-1);
            q.push(qwe(u.d,u.l,u.p-1,nw.second,nw.first));
        }
        if(u.p+1<=u.r)
        {
            pair<long long,int>nw=ques(rt[u.d],1,n,u.p+1,u.r);
            q.push(qwe(u.d,u.p+1,u.r,nw.second,nw.first));
        }
    }
    printf("%lld\n",ans);
    return 0;
}

以上是关于bzoj 4504: K个串大根堆+主席树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4504: K个串

[bzoj P4504] K个串

K Seq HihoCoder - 1046 || BZOJ4504 k个串

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

BZOJ4919[Lydsy六月月赛]大根堆 线段树合并

BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶