思路:把正负分开做,以正数为例,按c[i]从大到小做,设其编号为x,若前x-1个位置没填满就填并造成贡献,否则能填在第x个位置就填并不贡献,否则随便扔到后面,造成负贡献。负的部分就是正的反过来。 树状数组就是维护前x个位置填了几个数的。
大样例过了,但56pts,第一个测试点就WA了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;
const int N=2e5+5;
pii c[N];
ll C[N];
bool cmp(pii x,pii y){
if(x.first!=y.first)return x.first>y.first;
else return x.second>y.second;
}
int t[N],n;
int lowbit(int x){
return x&-x;
}
void add(int x,int v){
for(int i=x;i<=n;i+=lowbit(i))t[i]+=v;
}
int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))ans+=t[i];
return ans;
}
void solve(){
memset(t,0,sizeof(t));
int cnt;
scanf("%d",&n);
for(int i=1,_;i<=n;i++)
scanf("%d",&_);
for(int i=1;i<=n;i++)
scanf("%lld",&C[i]);
ll ans=0;
cnt=0;
for(int i=1,j=1;i<=n;i++)
if(C[i]>0ll){
c[j]={C[i],i};
j++;
cnt++;
}
sort(c+1,c+1+cnt,cmp);
memset(t,0,sizeof(t));
for(int i=1;i<=cnt;i++){
ll w=c[i].first;
int x=c[i].second;
if(x>cnt)ans+=w;
else{
if(query(x-1)<x-1){
add(x-1,1);
ans+=w;
}
else if(query(x)<x)
add(x,1);
else ans-=w;
}
}
cnt=0;
for(int i=1,j=1;i<=n;i++)
if(C[i]<0ll){
c[j]={-C[i],n+1-i};
j++;
cnt++;
}
sort(c+1,c+1+cnt,cmp);
memset(t,0,sizeof(t));
for(int i=1;i<=cnt;i++){
ll w=c[i].first;
int x=c[i].second;
if(x>cnt)ans+=w;
else{
if(query(x-1)<x-1){
add(x-1,1);
ans+=w;
}
else if(query(x)<x)
add(x,1);
else ans-=w;
}
}
printf("%lld\n",ans);
}
int main(){
// freopen("contrib.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)solve();
return 0;
}