#贪心,KTT#CF573E Bear and Bowling

题目传送门


分析

考虑贪心,从空集开始每次选择增量最大的位置添加进集合,答案为每种大小集合的答案的最大值

增量与当前位置之前的选择数字个数以及之后的和有关,也就是 \(\Delta=a_i\cdot cnt+sum\) 是一次函数的形式。

每次添加完集合相当于把一段后缀的 cnt 加一,再把前缀加上 \(a_i\),同时把 \(i\) 所在位置的增量改成负无穷,那么前者用 KTT 实现后者直接打懒标记就可以了


代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long lll; const lll inf=1e18;
const int N=100011; int a[N],n; lll now,ans;
struct Segment_Tree{
	lll K[N<<2],B[N<<2],P[N<<2],bound[N<<2],lazy[N<<2],lazy2[N<<2];
	void pmax(lll k1,lll b1,int p1,lll k2,lll b2,int p2,lll &k,lll &b,lll &p,lll &bound){
		if (b1<b2||(b1==b2&&k1<k2)) swap(k1,k2),swap(b1,b2),swap(p1,p2);
		k=k1,b=b1,p=p1;
		if (k1<k2) bound=min(bound,(b1-b2)/(k2-k1));
	}
	void pup(int k){
		bound[k]=min(bound[k<<1],bound[k<<1|1]);
		pmax(K[k<<1],B[k<<1],P[k<<1],K[k<<1|1],B[k<<1|1],P[k<<1|1],K[k],B[k],P[k],bound[k]);
	}
	void ptag(int k,lll z){
		B[k]+=K[k]*z,lazy[k]+=z;
		if (bound[k]!=inf) bound[k]-=z;
	}
	void build(int k,int l,int r){
		lazy[k]=lazy2[k]=0;
		if (l==r){
			K[k]=a[l],B[k]=a[l],P[k]=l,bound[k]=inf;
			return;
		}
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pup(k);
	}
	void update(int k,int l,int r,int x,int y,lll z){
		if (l==x&&r==y&&z<=bound[k]){
			ptag(k,z);
			return;
		}
		int mid=(l+r)>>1;
		if (lazy[k]){
			ptag(k<<1,lazy[k]);
			ptag(k<<1|1,lazy[k]);
			lazy[k]=0;
		}
		if (lazy2[k]){
			B[k<<1]+=lazy2[k],lazy2[k<<1]+=lazy2[k],
			B[k<<1|1]+=lazy2[k],lazy2[k<<1|1]+=lazy2[k],lazy2[k]=0;
		}
		if (y<=mid) update(k<<1,l,mid,x,y,z);
		    else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
		        else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
		pup(k);
	}
	void update2(int k,int l,int r,int x,int y,lll z){
		if (l==x&&r==y){
			B[k]+=z,lazy2[k]+=z;
			return;
		}
		int mid=(l+r)>>1;
		if (lazy[k]){
			ptag(k<<1,lazy[k]);
			ptag(k<<1|1,lazy[k]);
			lazy[k]=0;
		}
		if (lazy2[k]){
			B[k<<1]+=lazy2[k],lazy2[k<<1]+=lazy2[k],
			B[k<<1|1]+=lazy2[k],lazy2[k<<1|1]+=lazy2[k],lazy2[k]=0;
		}
		if (y<=mid) update2(k<<1,l,mid,x,y,z);
		    else if (x>mid) update2(k<<1|1,mid+1,r,x,y,z);
		        else update2(k<<1,l,mid,x,mid,z),update2(k<<1|1,mid+1,r,mid+1,y,z);
		pup(k);
	}
}Tre;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for (int i=1;i<=n;++i) cin>>a[i];
	Tre.build(1,1,n);
	for (int i=1;i<=n;++i){
		int t=Tre.P[1];
		ans=max(ans,now+=Tre.B[1]);
		Tre.update2(1,1,n,t,t,-inf);
		if (t>1) Tre.update2(1,1,n,1,t-1,a[t]);
		if (t<n) Tre.update(1,1,n,t+1,n,1);
	}
	cout<<ans;
	return 0;
}
posted @ 2026-10-10 10:08  lemondinosaur  阅读(7)  评论(0)    收藏  举报