用权值线段树维护了前 i 个数里 k 个最小的数之和(离散化了一下 a 数组),但是交上去 TLE On#7.
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
inline int read(){
int ret=0;
char c=getchar();
while(!('0'<=c&c<='9')) c=getchar();
while('0'<=c&&c<='9') ret=(ret<<1)+(ret<<3)+(c^48),c=getchar();
return ret;
}
int T,n,k;
const int N=2e5+10;
struct obj{ int x,y; } a[N];
bool cmp(obj &xx,obj &yy){ return xx.y>yy.y; }
int c[N];
inline int getid(int x){
int l=1,r=n,mid;
while(l<r){
mid=(l+r)>>1;
if(c[mid]>=x) r=mid;
else l=mid+1;
}
return l;
}
struct NODE{
int l,r;
ll cnt,sum;
} tr[N<<1];
inline void pushup(NODE &root,NODE &zuo,NODE &you){
root.sum=zuo.sum+you.sum;
root.cnt=zuo.cnt+you.cnt;
}
inline void pushup(int u){
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r){
tr[u]=(NODE){l,r};
if(l==r){
tr[u]=(NODE){l,r,0,0};
return ;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int k){
if(tr[u].l==tr[u].r){
tr[u].cnt++;
tr[u].sum+=c[k];
return ;
}
int mid=(tr[u].l+tr[u].r)>>1;
if(k<=mid) modify(u<<1,k);
else modify(u<<1|1,k);
pushup(u);
}
ll query(int u,ll res){ //查询前res小的数之和
if(tr[u].l==tr[u].r) return res*c[tr[u].l];
if(res==0) return 0;
if(tr[u].cnt==res) return tr[u].sum;
if(tr[u<<1].cnt>=res) return query(u<<1,res);
res-=tr[u<<1].cnt;
return tr[u<<1].sum+query(u<<1|1,res);
}
int main(){
T=read();
while(T--){
n=read(),k=read();
ll ans=0,ma=0;
build(1,1,n);
for(int i=1;i<=n;i++){
a[i].x=read();
c[i]=a[i].x;
}
sort(c+1,c+1+n);
for(int i=1;i<=n;i++){
a[i].y=read();
if(a[i].y>a[i].x) ans+=a[i].y-a[i].x; //后半部分只要Alice能赚到的都选上
}
if(k==0) ma=ans;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
modify(1,getid(a[i].x));
if(a[i].y>a[i].x) ans-=a[i].y-a[i].x;
if(i>=k) ma=max(ma,ans-query(1,k));
}
printf("%lld\n",ma);
}
return 0;
}