Description
兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一
个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。
兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第
k大的和是多少。
1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9数据保证存在第 k 大的和
Solution
非常套路的套路题
我们开n棵线段树,第i棵的第j个位置代表右端点为i,左端点为j时的答案,每次区间更改贡献求最大值
然后开一个堆记录最大值和最大值对应的区间。我们每次取出最大值然后把可行区间裂成两半再塞回去,做k次就没了
使用标记永久化可以更加精简和省内存
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fi first
#define se second
typedef long long LL;
typedef std:: pair <LL,int> pair;
const LL INF=1e15;
const int N=200005;
struct treeNode {int l,r; LL tag; pair max;} t[N*51];
struct data {
int i,l,r; pair max;
bool operator <(data b) const {
return max<b.max;
}
} ;
std:: map <int,int> last;
std:: priority_queue <data> heap;
int pre[N],root[N],a[N],tot;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void modify(int &now,int pre,int tl,int tr,int l,int r,int v) {
if (r<l) return ;
t[now=++tot]=t[pre];
if (tl>=l&&tr<=r) {
t[now].tag+=v;
t[now].max.fi+=v;
return ;
}
int mid=(tl+tr)>>1;
modify(t[now].l,t[pre].l,tl,mid,l,std:: min(r,mid),v);
modify(t[now].r,t[pre].r,mid+1,tr,std:: max(mid+1,l),r,v);
pair qx=t[t[now].l].max; qx.fi+=t[now].tag;
pair qy=t[t[now].r].max; qy.fi+=t[now].tag;
t[now].max=std:: max(qx,qy);
}
pair query(int now,int tl,int tr,int l,int r) {
if (r<l) return pair(-INF,0);
if (tl>=l&&tr<=r) return t[now].max;
int mid=(tl+tr)>>1;
pair qx=query(t[now].l,tl,mid,l,std:: min(r,mid)); qx.fi+=t[now].tag;
pair qy=query(t[now].r,mid+1,tr,std:: max(mid+1,l),r); qy.fi+=t[now].tag;
return std:: max(qx,qy);
}
void build_tree(int &now,int tl,int tr) {
t[now=++tot].max=pair(0,tl);
if (tl==tr) return ;
int mid=(tl+tr)>>1;
build_tree(t[now].l,tl,mid);
build_tree(t[now].r,mid+1,tr);
}
int main(void) { t[0].max=pair(-INF,0);
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),m=read();
build_tree(root[0],1,n);
rep(i,1,n) {
a[i]=read();
pre[i]=last[a[i]];
last[a[i]]=i;
modify(root[i],root[i-1],1,n,pre[i]+1,i,a[i]);
pair wjp=query(root[i],1,n,1,i);
heap.push((data) {i,1,i,query(root[i],1,n,1,i)});
}
LL ans=0;
for (pair max,wjp;m--;) {
data top=heap.top(); heap.pop();
int i=top.i; max=top.max; ans=max.fi;
if (max.se+1<=top.r) {
wjp=query(root[i],1,n,max.se+1,top.r);
heap.push((data) {i,max.se+1,top.r,wjp});
}
if (top.l<=max.se-1) {
wjp=query(root[i],1,n,top.l,max.se-1);
heap.push((data) {i,top.l,max.se-1,wjp});
}
}
printf("%lld\n", ans);
return 0;
}