CF709 C. Skyline Photo(线段树优化DP)

CF709 C. Skyline Photo(线段树优化DP)

传送门

题意:给两个数组,分别表示分数和高度,你可以将数组分成若干段,每段贡献为其高度最低的分数,求最高分数和。

题解:

好题,首先先考虑n*n做法,f[i]表示将前i段分成若干段的最大值,则f[n]即表示答案,易得递推方程:f[i]=max(f[i], f[j]+区间最低高度的分数)

所以我们便可以用线段树优化,处理区间最低高度的分数与f[j]的最大值。

然后每次循环开始时,第i个高度,会使一段区间的最低高度改变,二分线段树找到最远影响位置,同时区间修改影响的高度与分数,易知分f的值不会改变,所以只需储存区间内f的最大值,在区间修改完分数后,区间最大值就是分数+f的最大值。

#include<iostream>
using namespace std;
#define ll long long
const ll N=3e5+7;
const ll inf=1e9;
ll n,b[N],a[N];
struct madoka{
	ll l;
	ll r;
	ll f;
	ll b;
	ll dp;
	ll sum;
}ma[N*4];
void build(ll l,ll r,ll k){
	ma[k].l=l;
	ma[k].r=r;
	if(l==r){
		ma[k].b=inf;
		return;
	}
	ll mid=(l+r)/2;
	build(l,mid,k*2);
	build(mid+1,r,k*2+1);
	ma[k].b=max(ma[k*2].b,ma[k*2+1].b);
}
void down(ll k){
	if(ma[k].f&&ma[k].l!=ma[k].r){
		ma[k*2].f=ma[k].f;
		ma[k*2].b=b[ma[k].f];
		ma[k*2].sum=ma[k*2].dp+a[ma[k].f];
		ma[k*2+1].f=ma[k].f;
		ma[k*2+1].b=b[ma[k].f];
		ma[k*2+1].sum=ma[k*2+1].dp+a[ma[k].f];
		ma[k].f=0;
	}
}
ll fin(ll k,ll h){
	down(k);
	if(ma[k].l==ma[k].r){
		return ma[k].l;
	}
	ll mid=(ma[k].l+ma[k].r)/2;
	if(ma[k*2].b>=h){
		return fin(k*2,h);
	}
	else{
		return fin(k*2+1,h);
	}
}
void up(ll k,ll l,ll r){
	down(k);
	if(l<=ma[k].l&&ma[k].r<=r){
		ma[k].b=b[r];
		ma[k].sum=a[r]+ma[k].dp;
		ma[k].f=r;
		return;
	}
	ll mid=(ma[k].l+ma[k].r)/2;
	if(l<=mid){
		up(k*2,l,r);
	}
	if(mid<r){
		up(k*2+1,l,r);
	}
	ma[k].dp=max(ma[k*2].dp,ma[k*2+1].dp);
	ma[k].sum=max(ma[k*2].sum,ma[k*2+1].sum);
	ma[k].b=max(ma[k*2].b,ma[k*2+1].b);
}
void up_dp(ll k,ll p,ll z){
	down(k);
	if(ma[k].l==ma[k].r){
		ma[k].dp=z;
		return;
	}
	ll mid=(ma[k].l+ma[k].r)/2;
	if(p<=mid){
		up_dp(k*2,p,z);
	}
	else{
		up_dp(k*2+1,p,z);
	}
	ma[k].dp=max(ma[k*2].dp,ma[k*2+1].dp);
	ma[k].sum=max(ma[k*2].sum,ma[k*2+1].sum);
	ma[k].b=max(ma[k*2].b,ma[k*2+1].b);
}
ll qry(ll k,ll l,ll r){
	down(k);
	if(l<=ma[k].l&&ma[k].r<=r){
		return ma[k].sum;
	}
	ll mid=(ma[k].l+ma[k].r)/2;
	ll res=-inf;
	if(l<=mid){
		res=max(res,qry(k*2,l,r));
	}
	if(mid<r){
		res=max(res,qry(k*2+1,l,r));
	}
	return res;
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&b[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	build(1,n,1);
	for(int i=1;i<=n;i++){
		ll p=fin(1,b[i]);
		up(1,p,i);
		ll mx=qry(1,1,i);
		up_dp(1,i+1,mx);
		if(i==n){
			printf("%lld
",mx);
		}
	}
}
原文地址:https://www.cnblogs.com/whitelily/p/14596540.html