像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(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. 忘掉VNC/RDP,拿起手中的MobaXterm轻松上手远程桌面

    前言 原创文章,转载引用务必注明链接. 这期属于番外篇,随便写写.吐槽一下自己,关于"减少eMMC擦写,延长NAND寿命提升性能"的坑还没填完,都不好愉快地写点轻松的小项目灌水了. ...

  2. AngularJs概述

  3. string方法 PadLeft 返回一个新字符串,该字符串通过在此实例中的字符左侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符右对齐。 PadRight 右边

  4. onedrive实现excel在线编辑 online excel

    1.首先用火狐浏览器或者谷歌浏览器登录 https://onedrive.live.com 2.注冊邮箱账户信息 3.在邮箱激活账户信息 4.登录进去.点击我的账户,点击左側文件树.点选上载,将文件上 ...

  5. opencvSGBM半全局立体匹配算法的研究(1)

    转载请说明出处:http://blog.csdn.net/zhubaohua_bupt/article/details/51866567 这段时间对opencvSGBM半全局立体匹配算法进行了比較仔细 ...

  6. JRE、JDK、JVM区别和联系

    首先说Java编程语言,它是一门高级编程语言,具体由谁何时创建的,读者可以到网上查找相关资料,这里就不再赘述.那么,谈到Java就不得不谈谈JVM.JRE和JDK三者间的区别和联系. JVM:英文全称 ...

  7. 怎样搭建svn本地server,管理本地的代码

    搭建svn本地server,以下是详细的步骤介绍. 一.准备工作 1.下载svnserver端:Subversion. 到官方站点(http://s version.tigris.org/)下载最新的 ...

  8. AndroidCityPicker仿IOS选择效果

    近期的一个项目由于android端与IOS端须要同步,所以在城市选择器这里做了一个相似IOS的CityPicker控件,当然由于本人水平问题显示效果比IOS上面还是有一定差距的.OK先让大家看下效果. ...

  9. js获取三天后的日期

    js获取三天后的日期 setDate getNowAddTreeFormatDate() { var date = new Date(); date.setDate(date.getDate()+3) ...

  10. luogu3379 【模板】最近公共祖先(LCA) 倍增法

    题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...