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个串【大根堆+主席树】的更多相关文章
- bzoj : 4504: K个串 区间修改主席树
4504: K个串 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 268 Solved: 110[Submit][Status][Discuss] ...
- bzoj 4504: K个串 可持久化线段树+堆
题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...
- BZOJ 4504: K个串
题目大意: 求一个序列的第k大的子串和. 题解: 对于一个右端点找最优的左端点,扔进堆里. 每次取堆顶,将这个右端点可以选择的左端点的区间分成两段,扔进堆里,重复k次. 现在需要对于一个固定的右端点, ...
- [bzoj P4504] K个串
[bzoj P4504] K个串 [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次 ...
- BZOJ2006[NOI2010]超级钢琴——堆+主席树
题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中 ...
- BZOJ 2006 超级钢琴(堆+主席树)
很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...
- 【BZOJ4504】K个串 可持久化线段树+堆
[BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...
- BZOJ 2006 [NOI2010]超级钢琴 (堆+主席树)
题面:BZOJ传送门 洛谷传送门 让你求前$K$大的子序列和,$n\leq 5*10^{5}$ 只想到了个$nlog^{2}n$的做法,似乎要被卡常就看题解了.. 好神奇的操作啊,我傻了 我们把序列和 ...
- 51nod K 汽油补给 大根堆+小根堆....
题目传送门 用优先队列瞎搞... 想着在每个地方 先算上一个点到这一个点要花费多少钱 这个用小根堆算就好 然后在这个地方加油 把油钱比自己多的替代掉 这个用大根堆维护一下 然后两个堆之间信息要保持互通 ...
随机推荐
- java cup占用高分析脚本
[was@dmgr ita-scripts]$ vi java_analys.sh PID=$1 ; ps -mp $PID -o THREAD,tid,time | awk -F " ...
- JSON JavaScriptSerializer 字符串的长度超过了为 maxJsonLength 属性设置的值。
1.序列化: 以下代码在对象过大时会报错:进行序列化或反序列化时出错.字符串的长度超过了为 maxJsonLength 属性设置的值. //jsonObj比较大的时候会报错 var serialize ...
- linux 输入子系统(4) intput_dev 接口描述
Name struct input_dev - represents an input device Synopsis struct input_dev { const char * name; // ...
- Javascript对象的技巧和陷阱
创建对象的3种方法 方法1 直接创建 var obj = { name: "mike", age: 10 } 方法2 用new创建 var ob = new Date(); 方法3 ...
- java File文件操作共用方法整理
package org.jelly.util; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io ...
- 在docker里查看java进程
先使用命令查看docker的运行进程 docker ps [root@localhost logs]# docker ps CONTAINER ID IMAGE ...
- noip2016前的话[漫谈]
今天是11月15日,离noip2016还剩三天: 今年我也是高二了,回首一下去年的时光,真的仿佛仍在昨天,我甚至现在还清楚的记得,当年那次我们做的每一件事: 星期五,回去与室友告别,得到了祝愿,乘公交 ...
- hdu 5615 Jam's math problem(十字相乘判定)
d. Jam有道数学题想向你请教一下,他刚刚学会因式分解比如说,x^2+6x+5=(x+1)(x+5) 就好像形如 ax^2+bx+c => pqx^2+(qk+mp)x+km=(px+k)(q ...
- CollapsingToolbarLayout 收缩显示tilte
final CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id. ...
- SPOJ:Lost and survived(multiset+并查集)
On September 22, 2004, Oceanic Flight 815 crashed on a mysterious island somewhere in the pacific. T ...