CF660F Bear and Bowling 4

https://www.luogu.com.cn/problem/CF660F

找区间的题想到分治。

假如考虑怎么计算跨 mid 的贡献。

假如 \(i\in [l,mid]\) 的答案为 \(ans_i\)(右端点为 \(mid\)),右边的答案为 \(j\in [mid+1,r],ans_j\) (左端点为 \(mid+1\)),那么答案显然是 \(ans_i+(mid-i+1)*sum_j+ans_j\),实际上就是把右边的看成一个个一次函数,求在 \(mid-i+1\) 的最大值。

李超线段树即可。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(2e5+5);
int n,a[N];
#define ls (cur<<1)
#define rs (ls|1)
struct node {
	int k,b;
}s[N];
int val[N<<2];

int cal(int id,int x) {
	return s[id].k*x+s[id].b;
}
int clr[N<<4],clrtot;
void update(int cur,int l,int r,int cl,int cr,int id) {
	int mid=(l+r)>>1,v=val[cur];
//	cout<<cur<<" "<<l<<" "<<r<<" "<<cl<<" "<<cr<<" "<<id<<'\n';
	if(cl<=l&&r<=cr) {
		clr[++clrtot]=cur;
		int res1=cal(v,mid),res2=cal(id,mid);
		if(l==r) {
			if(!val[cur]) val[cur]=id;
			else {	
				if(res2>res1) val[cur]=id;	
			}
			return ;
		}
		if(s[id].k>s[v].k) {
			if(res2>res1) val[cur]=id,update(ls,l,mid,cl,cr,v);
			else update(rs,mid+1,r,cl,cr,id);
		} else if(s[id].k<s[v].k) {
			if(res2>res1) val[cur]=id,update(rs,mid+1,r,cl,cr,v);
			else update(ls,l,mid,cl,cr,id);
		} else if(s[id].b>s[v].b) val[cur]=id;
		return ;
	}
	if(cl<=mid) update(ls,l,mid,cl,cr,id);
	if(cr>mid) update(rs,mid+1,r,cl,cr,id);
}
// 标记永久化

int query(int cur,int l,int r,int pos) {
	if(r<pos||l>pos) return 0;
	int mid=(l+r)>>1,res=cal(val[cur],pos);
	if(l==r) return res;
	if(pos<=mid) res=max(res,query(ls,l,mid,pos));
	else res=max(res,query(rs,mid+1,r,pos));
	return res;
}

void RE(int cur,int l,int r) {
	val[cur]=0;
	if(l==r) return ;
	int mid=(l+r)>>1;
	RE(ls,l,mid); RE(rs,mid+1,r);
}

int ans=0,tmp[N],sm[N];
void solve(int l,int r) {
	if(l==r) {
		ans=max(ans,a[l]); return ;
	}
	int mid=(l+r)>>1;
//	cout<<l<<' '<<r<<'\n';
	solve(l,mid); solve(mid+1,r);
	tmp[mid]=sm[mid]=0; int cnt=0;
	for(int i=mid+1;i<=r;i++) {
		tmp[i]=tmp[i-1]+(i-mid)*a[i];
		sm[i]=sm[i-1]+a[i];
		s[++cnt].k=sm[i]; s[cnt].b=tmp[i];
	}
	clrtot=0;
	for(int i=1;i<=cnt;i++) update(1,1,n,1,n,i);
	int res=0;
	for(int i=l;i<=mid;i++) res+=+a[i]*(i-l+1);
	int qwq=0;
	for(int i=l;i<=mid;i++) qwq+=a[i];
	for(int i=l;i<=mid;i++) {
//		int nw=0;
//		for(int j=l;j<=mid;j++) nw+=(j-l+1)*a[j];
		ans=max(ans,res+query(1,1,n,mid-i+1));
		res-=qwq; qwq-=a[i];
	}
	for(int i=1;i<=clrtot;i++) val[clr[i]]=0;
	for(int i=l;i<=r;i++) tmp[i]=sm[i]=0;
}

signed main() {
//	cin.tie(0); ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	solve(1,n); cout<<ans;
	return 0;
}


posted @ 2022-07-14 13:11  FxorG  阅读(32)  评论(0编辑  收藏  举报