像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(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个串【大根堆+主席树】的更多相关文章

  1. bzoj : 4504: K个串 区间修改主席树

    4504: K个串 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 268  Solved: 110[Submit][Status][Discuss] ...

  2. bzoj 4504: K个串 可持久化线段树+堆

    题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...

  3. BZOJ 4504: K个串

    题目大意: 求一个序列的第k大的子串和. 题解: 对于一个右端点找最优的左端点,扔进堆里. 每次取堆顶,将这个右端点可以选择的左端点的区间分成两段,扔进堆里,重复k次. 现在需要对于一个固定的右端点, ...

  4. [bzoj P4504] K个串

    [bzoj P4504] K个串 [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次 ...

  5. BZOJ2006[NOI2010]超级钢琴——堆+主席树

    题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中 ...

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

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

  7. 【BZOJ4504】K个串 可持久化线段树+堆

    [BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...

  8. BZOJ 2006 [NOI2010]超级钢琴 (堆+主席树)

    题面:BZOJ传送门 洛谷传送门 让你求前$K$大的子序列和,$n\leq 5*10^{5}$ 只想到了个$nlog^{2}n$的做法,似乎要被卡常就看题解了.. 好神奇的操作啊,我傻了 我们把序列和 ...

  9. 51nod K 汽油补给 大根堆+小根堆....

    题目传送门 用优先队列瞎搞... 想着在每个地方 先算上一个点到这一个点要花费多少钱 这个用小根堆算就好 然后在这个地方加油 把油钱比自己多的替代掉 这个用大根堆维护一下 然后两个堆之间信息要保持互通 ...

随机推荐

  1. 重装系统(Win)

    有朋友问我,重装系统该怎样操作呢? 1. 硬盘重装 官网:http://www.heiyunwang.com/ ,点击下载软件:http://dlsw.baidu.com/sw-search-sp/s ...

  2. 用Meta 取消流量器缓存方便调试

    <!-- 禁止浏览器从本地缓存中调阅页面.--> <meta http-equiv="pragram" content="no-cache"& ...

  3. qt动画入门

    Qt-4.6新增了Animation Framework(动画框架),让我们可以方便的写一些生动的程序. 不必像曾经的版本号一样,全部的控件都枯燥的呆在伟大光荣的QLayout里,或许它们可以唱个歌, ...

  4. TCP 的那些事儿(下)(转)

    TCP的RTT算法 从前面的TCP的重传机制我们知道Timeout的设置对于重传非常重要, 设长了,重发就慢,没有效率,性能差: 设短了,重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多 ...

  5. Ubuntu 14.04安装搜狗拼音linux版应该注意的问题

    Ubuntu 14.04最终在万千期盼中来了,我也像其他的linux爱好者一样,删除了旧的12.04.開始体验下一个到来的LTS版本号. 我不想安装Ubuntu 麒麟版,我仅仅想原汁原味的Ubuntu ...

  6. Redis 脚本及其应用

    参考:http://www.runoob.com/redis/redis-scripting.html Redis 脚本使用 Lua 解释器来执行脚本. Reids 2.6 版本通过内嵌支持 Lua ...

  7. 64位CentOs7源码安装mysql-5.6.35过程分享

    首先安装依赖包,避免在安装过程中出现问题 [root@bogon liuzhen]# yum -y install gcc gcc-c++[root@bogon liuzhen]# yum -y in ...

  8. Python中怎样用pip安装外部主机文件

    在python中安装非自带python模块.有三种方式: easy_install pip 下载压缩包(.zip, .tar, .tar.gz)后解压, 进入解压缩的文件夹后运行python setu ...

  9. Mac 上VitrualBox安装CentOS6.5 调整root分区的大小

    安装centOS的时候由于选择了动态调整磁盘大小.所以分配磁盘空间的时候就没多想,直接用的default的8G,以为不够了自己会调整,没想到是个大坑 发现提示空间不足的时候root仅仅有0k了.... ...

  10. block-循环引用

    在ARC机制下,app的内存管理由操作系统进行管理,不须要程序猿手动的管理内存,方便了开发.虽然,自己主动释放内存非常方便.可是并不是绝对安全,绝对不会产生内存泄露. 大部分导致iOS对象无法按预期释 ...