线段树+思维 推销员(洛谷 P2672)

推销员

题目描述

阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为 Si 米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。
阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

输入格式

第一行有一个正整数N,表示螺丝街住户的数量。

接下来的一行有N个正整数,其中第 i 个整数 Si 表示第i家住户到入口的距离。数据保证 S_1≤S_2≤…≤S_n<10^8 接下来的一行有N个正整数,其中第 i 个整数A_i表示向第i户住户推销产品会积累的疲劳值。数据保证A_i<1000

输出格式

输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。


线段树维护区间最大值;、

记录前 i-1 户住户距离的最大值mxl,若第 i 户距离比最大值小,那么没有任何操作;
若比最大值大,那么mxl-第i户的值变为该户的疲劳值,第 i+1 户到第 n 户的值减去第 i 户到mxl户的距离;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=100010;
const int M=2000100;
const LL mod=2e9;
int n,s[N],a[N];
struct Node{
	int l,r,num;
	LL mx,lt;
}tr[N*4];
void pp(int k){
	if(tr[ls].mx>=tr[rs].mx) tr[k].mx=tr[ls].mx,tr[k].num=tr[ls].num;
	else tr[k].mx=tr[rs].mx,tr[k].num=tr[rs].num;
}
void pd(int k){
	if(tr[k].lt){
		tr[ls].mx-=tr[k].lt;
		tr[rs].mx-=tr[k].lt;
		tr[ls].lt+=tr[k].lt;
		tr[rs].lt+=tr[k].lt;
	}
	tr[k].lt=0;
}
void build(int l,int r,int k){
	tr[k].l=l,tr[k].r=r;
	if(l==r){
		tr[k].mx=(LL)(2*s[l]+a[l]);
		tr[k].num=l;
		return;
	}
	int d=(l+r)>>1;
	build(l,d,ls);
	build(d+1,r,rs);
	pp(k);
}
void update1(int l,int r,int k){
	if(tr[k].mx<=0||l>r) return;
	if(tr[k].l==tr[k].r){
		tr[k].mx=a[tr[k].num];
		return;
	}
	pd(k);
	int d=(tr[k].l+tr[k].r)>>1;
	if(l<=d) update1(l,r,ls);
	if(r>d) update1(l,r,rs);
	pp(k);
}
void update2(int l,int r,LL w,int k){
	if(tr[k].mx<=0||l>r) return;
	if(tr[k].l>=l&&tr[k].r<=r){
		tr[k].mx-=w;
		tr[k].lt+=w;
		return;
	}
	pd(k);
	int d=(tr[k].l+tr[k].r)>>1;
	if(l<=d) update2(l,r,w,ls);
	if(r>d) update2(l,r,w,rs);
	pp(k);
}
void dele(int pos,int k){
	if(tr[k].l==tr[k].r){
		tr[k].mx=0;
		return;
	}
	pd(k);
	int d=(tr[k].l+tr[k].r)>>1;
	if(pos<=d) dele(pos,ls);
	else dele(pos,rs);
	pp(k);
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,n,1);
	LL ans=0;
	int mxl=0;
	for(int i=1;i<=n;i++){
		ans+=tr[1].mx;
		int k=tr[1].num;
		if(k>mxl){
			update1(mxl+1,k-1,1);
			update2(k+1,n,2ll*(s[k]-s[mxl]),1);
			mxl=k;
		}
		printf("%d\n",ans);
		dele(k,1);
	}
	return 0;
}
发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/105268728
今日推荐