题解: 我们考虑到查询区间类不同数目的个数在线做法是主席树维护,然后我们可以维护出每个位置的值产生贡献的范围,然后相当于主席树维护了以i为右端点,[j,i]的不同数字的和 然后考虑到这题的K在可接受的范围内 所以我们采用分裂的方式 即维护每个右端点里面的最大值 然后优先队列维护五元组 找出第K大 时间复杂度是(n+k)logn
#include <bits/stdc++.h>
#define ll long long
#define pii pair<ll,int>
const int MAXN=1e5+10;
const ll inf=1e18;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,k;
typedef struct node{
int l,r,pos;ll sum,maxx;
}node;
node d[MAXN*101];
int rt[MAXN];
int cnt;int cnt1;
void up(int x,int l,int r){
d[x].maxx=d[d[x].l].maxx;d[x].pos=l;
if(d[x].l)d[x].pos=d[d[x].l].pos;
if(d[d[x].r].maxx>d[x].maxx)d[x].maxx=d[d[x].r].maxx,d[x].pos=d[d[x].r].pos;
if(!d[x].pos)d[x].pos=((l+r)>>1)+1;
d[x].maxx+=d[x].sum;
}
void update(int &x,int y,int l,int r,int ql,int qr,ll vul){
// cout<<l<<"====="<<r<<" "<<vul<<" "<<ql<<" "<<qr<<endl;
x=++cnt;d[x]=d[y];
if(!d[x].pos)d[x].pos=l;
if(ql<=l&&r<=qr){d[x].sum+=vul;d[x].maxx+=vul;return ;}
int mid=(l+r)>>1;
if(ql<=mid)update(d[x].l,d[y].l,l,mid,ql,qr,vul);
if(qr>mid)update(d[x].r,d[y].r,mid+1,r,ql,qr,vul);
up(x,l,r);
// cout<<d[x].maxx<<"::::"<<" "<<d[x].pos<<" "<<ql<<" "<<qr<<endl;
}
pii aim;bool flag;
void querty(int x,int l,int r,int ql,int qr,ll key){
// cout<<l<<" "<<r<<" "<<ql<<" "<<qr<<" "<<aim.first<<" "<<aim.second<<" "<<d[x].maxx<<endl;
if(!x){
if(!flag){
aim.first=key,aim.second=max(l,ql),flag=1;
}
else{
if(aim.first<key)aim.first=key,aim.second=max(l,ql);
}
return ;
}
if(ql<=l&&r<=qr){
if(!flag)aim.first=key+d[x].maxx,aim.second=d[x].pos,flag=1;
else{if(aim.first<key+d[x].maxx)aim.first=key+d[x].maxx,aim.second=d[x].pos;}
return ;
}
int mid=(l+r)>>1;
if(ql<=mid)querty(d[x].l,l,mid,ql,qr,key+d[x].sum);
if(qr>mid)querty(d[x].r,mid+1,r,ql,qr,key+d[x].sum);
}
vector<ll>vec;
ll a[MAXN];
int pre[MAXN];
typedef struct Node{
int l,r,rx,pos;ll vul;
friend bool operator<(Node aa,Node bb){
return aa.vul<bb.vul;
}
}Node;
priority_queue<Node>que;
int main(){
n=read();k=read();
for(int i=1;i<=n;i++)a[i]=read(),vec.push_back(a[i]);
sort(vec.begin(),vec.end());
int sz=unique(vec.begin(),vec.end())-vec.begin();
for(int i=1;i<=n;i++)a[i]=lower_bound(vec.begin(),vec.begin()+sz,a[i])-vec.begin()+1;
for(int i=1;i<=n;i++){update(rt[i],rt[i-1],1,n,pre[a[i]]+1,i,vec[a[i]-1]);pre[a[i]]=i;}
for(int i=1;i<=n;i++){
Node t;t.l=1;t.r=i;t.rx=i;
aim.first=0;aim.second=0;
flag=0;querty(rt[i],1,n,1,i,0);
t.pos=aim.second;t.vul=aim.first;
// cout<<t.pos<<"======------"<<t.vul<<endl;
que.push(t);
}
for(int i=1;i<k;i++){
Node t=que.top();que.pop();
if(t.pos>t.l){
Node t1;t1.l=t.l;t1.r=t.pos-1;t1.rx=t.rx;
flag=0;querty(rt[t.rx],1,n,t.l,t.pos-1,0);
t1.pos=aim.second;t1.vul=aim.first;
que.push(t1);
}
if(t.pos<t.r){
Node t2;t2.l=t.pos+1;t2.r=t.r;t2.rx=t.rx;
flag=0;querty(rt[t.rx],1,n,t.pos+1,t.r,0);
t2.pos=aim.second;t2.vul=aim.first;
que.push(t2);
}
}
printf("%lld\n",que.top().vul);
return 0;
}
4504: K个串
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 517 Solved: 200
[Submit][Status][Discuss]
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
3 -2 1 2 2 1 3 -2
Sample Output
4
HINT
1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9数据保证存在第 k 大的和