CF182C
根据贪心策略,应当选择 \(k\) 个最小的负数改为正数,或选择 \(k\) 个最大的正数改为负数,才可能使答案最大。那么可以先把数按正负分开,并确定每个数在同符号数中的排名。建立权值线段树,记录每个数出现的次数、单个数大小、总贡献和,查询时类似线段树二分,如果数值较大的区间不够用,就往数值较小的区间递归,否则在其内部递归。循环时分别维护当前的正数和、负数和。时间复杂度 \(O(n\log n)\)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 200010
#define int long long
using namespace std;
struct node{
int val,siz,v;
};
struct T{
node t[N*4];
void pushup(int u){
t[u].val=t[u<<1].val+t[u<<1|1].val;
t[u].siz=t[u<<1].siz+t[u<<1|1].siz;
}
void upd(int u,int l,int r,int p,int v,int ki){
if(l==r){
t[u].v=v;
t[u].siz+=ki;
t[u].val=t[u].siz*v;
return;
}
int mid=(l+r)>>1;
if(p<=mid)upd(u<<1,l,mid,p,v,ki);
if(p>mid)upd(u<<1|1,mid+1,r,p,v,ki);
pushup(u);
}
int que(int u,int l,int r,int nw){
if(l>r||nw==0)return 0;
// cout<<l<<' '<<r<<endl;
if(l==r)return t[u].v*min(t[u].siz,nw);
int mid=(l+r)>>1;
if(t[u<<1|1].siz>=nw)return que(u<<1|1,mid+1,r,nw);
else return t[u<<1|1].val+que(u<<1,l,mid,nw-t[u<<1|1].siz);
}
}tp,tn;
struct L{
int val,ki,id;
}a[N];
int n,len,pm,nm,k,pa[N],na[N],sp,sn,ans;
void modify(int i,int val){
if(a[i].ki==-1)tn.upd(1,1,nm,a[i].id,a[i].val,val);
if(a[i].ki==1)tp.upd(1,1,pm,a[i].id,a[i].val,val);
}
signed main(){
cin>>n>>len;
for(int i=1;i<=n;i++){
cin>>a[i].val;
if(a[i].val<0)a[i].val*=-1,a[i].ki=-1,na[++nm]=a[i].val;
else if(a[i].val>0)a[i].ki=1,pa[++pm]=a[i].val;
}
cin>>k;
sort(pa+1,pa+pm+1);sort(na+1,na+nm+1);
nm=unique(na+1,na+nm+1)-na-1;
pm=unique(pa+1,pa+pm+1)-pa-1;
for(int i=1;i<=n;i++){
if(a[i].ki==-1)a[i].id=lower_bound(na+1,na+nm+1,a[i].val)-na;
if(a[i].ki==1)a[i].id=lower_bound(pa+1,pa+pm+1,a[i].val)-pa;
// cout<<i<<' '<<a[i].id<<endl;
}
for(int i=1;i<len;i++){
modify(i,1);
if(a[i].ki==-1)sn+=a[i].val;
else sp+=a[i].val;
}
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
modify(j,1);
if(a[j].ki==-1)sn+=a[j].val;
else sp+=a[j].val;
// cout<<1<<endl;
ans=max(ans,abs(sn+tp.que(1,1,pm,k)-(sp-tp.que(1,1,pm,k))));
ans=max(ans,abs(sp+tn.que(1,1,nm,k)-(sn-tn.que(1,1,nm,k))));
// cout<<i<<' '<<j<<' '<<sn<<' '<<sp<<' '<<abs(sn+tp.que(1,1,pm,k)-(sp-tp.que(1,1,pm,k)))<<' '<<abs(sp+tn.que(1,1,nm,k)-(sn-tn.que(1,1,nm,k)))<<endl;
modify(i,-1);
if(a[i].ki==-1)sn-=a[i].val;
else sp-=a[i].val;
}
cout<<ans;
return 0;
}
我们会走到一起的。