线段树TLE求助,复杂度哪里假了(悬关)
查看原帖
线段树TLE求助,复杂度哪里假了(悬关)
881015
Resstifnurvˆwˆ.tar.gz楼主2024/5/2 02:20

用权值线段树维护了前 ii 个数里 kk 个最小的数之和(离散化了一下 aa 数组),但是交上去 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;
}
2024/5/2 02:20
加载中...