版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/84030103
解题思路:首先求第k小的答案,通常套路都是二分答案,然后判断有多少个答案比他小即可。
关键在于如何高效的判断有多少个答案比他小,如果我们把所有答案预处理出来,复杂度是N^2级别的,但是我们不必把所有答案都预处理出来,我们只需要知道有多少个比他小即可。因此我们可以通过各种数据结构,高效的查询有多少个比他小即可。这样复杂度就可以去到NLogN了。这里需要巧妙地转化,使得可以在O(NlogN)的时间内查询有多少个点比他小。附上官方题解!
最后我们可以用权值线段树或者树状数组即可快速查询,查询前把所有的b区间和 g都离散化即可。lower_bound注意-1的问题。
注意K要--,因为第1小其实是没有任何数比他小。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=40005;
const int MAXM=MAXN*3;
ll a[MAXN];
ll b[MAXN];
ll c[MAXN];
ll suma[MAXN];
ll sumb[MAXN];
ll sumc[MAXN];
ll g[MAXN];
ll f[MAXN];
ll sorted[MAXN*5];
int tot=0;
int N,R;
ll K;
ll tree[MAXM<<2];
void update(int L,ll C,int l,int r,int rt){
if(l==r){
tree[rt]+=C;
return;
}
int m=(l+r)/2;
if(L<=m)
update(L,C,l,m,rt<<1);
else
update(L,C,m+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
ll query(int L,int R,int l,int r,int rt){
if(R<L)
return 0;
if(L<=l&&r<=R)
return tree[rt];
int m=(l+r)/2;
ll ans=0;
if(L<=m)
ans+=query(L,R,l,m,rt<<1);
if(R>m)
ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int id(ll num){
return lower_bound(sorted,sorted+tot,num)-sorted+1;
}
bool judge(ll s){
ll rank=0;
memset(tree,0,sizeof(tree));
for(int i=R+1,j=1;i+R-1<=N;i++,j++){
update(id(sumb[j+R-1]-sumb[j-1]),1,1,MAXM,1);
rank+=query(1,id(s-(sumb[i+R-1]-sumb[i-1]))-1,1,MAXM,1);
}
memset(tree,0,sizeof(tree));
for(int i=2;i+R-1<=N;i++){
update(id(g[i-1]),1,1,MAXM,1);
if(i-R>=1)
update(id(g[i-R]),-1,1,MAXM,1);
rank+=query(1,id(s-f[i])-1,1,MAXM,1);
}
return rank<=K;
}
int main()
{
scanf("%d%d%lld",&N,&R,&K);
K--;//pay attention
for(int i=1;i<=N;i++){
scanf("%lld",&a[i]);
suma[i]=suma[i-1]+a[i];
}
for(int i=1;i<=N;i++){
scanf("%lld",&b[i]);
sumb[i]=sumb[i-1]+(b[i]-a[i]);
}
for(int i=1;i<=N;i++){
scanf("%lld",&c[i]);
sumc[i]=sumc[i-1]+(c[i]-a[i]);
}
for(int i=1;i+R-1<=N;i++){
g[i]=(sumc[i-1]-2*sumb[i-1])+(sumc[i+R-1]-sumb[i+R-1])-(sumc[i-1]-sumb[i-1]);
f[i]=(2*sumb[i-1]-sumc[i-1])+(sumb[i+R-1])-(sumb[i-1]);
}
//li san hua
for(int i=1;i<=N;i++){
if(i>=R){
sorted[tot++]=g[i-R+1];
sorted[tot++]=sumb[i]-sumb[i-R];
}
}
sort(sorted,sorted+tot);
tot=unique(sorted,sorted+tot)-sorted;
ll l=0,r=1000000000000ll;
while(l+1<r){
ll m=(l+r)/2;
if(judge(m))
l=m;
else
r=m;
}
printf("%lld\n",l+suma[N]);
return 0;
}