Description
兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一
个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。
兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第
k大的和是多少。
Input
第一行,两个整数n和k,分别表示长度为n的数字序列和想要统计的第k大的和
接下里一行n个数a_i,表示这个数字序列
Output
一行一个整数,表示第k大的和
Sample Input
7 5
3 -2 1 2 2 1 3 -2
Sample Output
4
HINT
1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9数据保证存在第 k 大的和
题意
给出一个数字序列,求第k大的去重之后的连续子序列的和.
做法
这题与[NOI2010]超级钢琴很像,但这题还需要去重.
我们可以根据右端点的位置来排序,这样如果一个点对这段区间有贡献.那么左端点就一定在该点上一次出现位置(如未出现,则为0)+1与该点位置之间,而且以第i个点为右端点与以第i+1个点为右端点的区间仅需考虑新加入的i+1点,[NOI2010]超级钢琴中,我们利用st表来维护区间最大值,这题则可以用线段树来维护,再利用右端点的移动对答案的影响很小的性质,可以建出主席树,加入点时,利用永久化标记(永远不会向子节点传递的标记,因为只需要维护区间最大值的位置,故可以打上这个标记)可以保证只增加log个的节点.
最后用优先队列维护,将结构体(l,r,mx,mx_pos,from)放入堆,这个结构体表示右端点为from(第from棵树),左端点在l~r时的最大值为mx,最大值的位置为max _pos,这样之后将结构体(l,max _pos-1,l~max _pos-1间的最大值及其位置)和结构体(max _pos+1,r,max _pos+1~r间的最大值及其位置)放入堆中,重复k-1次,堆顶即为答案.
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#define ll long long
#define P pair<ll,ll>
#define mp make_pair
#define fi first
#define se second
#define mid ((l+r)>>1)
#define N 100100
using namespace std;
ll n,m,root[N],tt;
P tp;
struct Node
{
ll max_pos,sum,left_son,right_son,mx;
}node[N*200];
struct Pm
{
ll left,right,max_pos,from,mx;
bool operator < (const Pm &u) const
{
return mx<u.mx;
}
}tmp,t2;
map<ll,ll>pre;
priority_queue<Pm>pq;
void build(ll now,ll l,ll r)
{
node[now].max_pos=l;
if(l==r) return;
node[now].left_son=++tt;
build(tt,l,mid);
node[now].right_son=++tt;
build(tt,mid+1,r);
}
void add(ll now,ll l,ll r,ll al,ll ar,ll u)
{
if(l==al&&r==ar)
{
node[now].sum+=u;
return;
}
if(mid>=ar)
{
node[++tt]=node[node[now].left_son];
node[now].left_son=tt;
add(tt,l,mid,al,ar,u);
}
else if(mid<al)
{
node[++tt]=node[node[now].right_son];
node[now].right_son=tt;
add(tt,mid+1,r,al,ar,u);
}
else
{
node[++tt]=node[node[now].left_son];
node[now].left_son=tt;
add(tt,l,mid,al,mid,u);
node[++tt]=node[node[now].right_son];
node[now].right_son=tt;
add(tt,mid+1,r,mid+1,ar,u);
}
if(node[node[now].left_son].sum+node[node[now].left_son].mx>node[node[now].right_son].sum+node[node[now].right_son].mx)
{
node[now].mx=node[node[now].left_son].sum+node[node[now].left_son].mx;
node[now].max_pos=node[node[now].left_son].max_pos;
}
else
{
node[now].mx=node[node[now].right_son].sum+node[node[now].right_son].mx;
node[now].max_pos=node[node[now].right_son].max_pos;
}
}
P ask(ll now,ll l,ll r,ll al,ll ar)
{
if(l==al&&r==ar)
{
return mp(node[now].mx+node[now].sum,node[now].max_pos);
}
if(mid>=ar)
{
P res=ask(node[now].left_son,l,mid,al,ar);
res.fi+=node[now].sum;
return res;
}
else if(mid<al)
{
P res=ask(node[now].right_son,mid+1,r,al,ar);
res.fi+=node[now].sum;
return res;
}
else
{
P res=max(ask(node[now].left_son,l,mid,al,mid),ask(node[now].right_son,mid+1,r,mid+1,ar));
res.fi+=node[now].sum;
return res;
}
}
int main()
{
ll i,j,p,q;
cin>>n>>m;
build(0,1,n);
for(i=1;i<=n;i++)
{
root[i]=++tt;
node[tt]=node[root[i-1]];
scanf("%lld",&p);
add(root[i],1,n,pre[p]+1,i,p);
pre[p]=i;
}
for(i=1;i<=n;i++)
{
tmp.from=i;
tmp.left=1;
tmp.right=i;
tp=ask(root[i],1,n,1,i);
tmp.mx=tp.fi;
tmp.max_pos=tp.se;
pq.push(tmp);
}
for(i=1;i<m;i++)
{
tmp=pq.top();
pq.pop();
t2=tmp;
t2.right=t2.max_pos-1;
if(t2.left<=t2.right)
{
tp=ask(root[t2.from],1,n,t2.left,t2.right);
t2.mx=tp.fi;
t2.max_pos=tp.se;
pq.push(t2);
}
t2=tmp;
t2.left=tmp.max_pos+1;
if(t2.left<=t2.right)
{
tp=ask(root[t2.from],1,n,t2.left,t2.right);
t2.mx=tp.fi;
t2.max_pos=tp.se;
pq.push(t2);
}
}
cout<<pq.top().mx;
}