线段树、贪心与推销员

[NOIP 2015] 推销员 - 洛谷

核心:利用线段树处理贪心内容。建两个线段树维护两端。

#include<bits/stdc++.h>
using namespace std;
int n;
int d[100100];
int t[1000100];
int deep;//当前最深 
int ans;
struct node{
	int id,mx;
};
struct sgt{
	int a[1000100];
	int mx[4000100];
	int id[4000100];
	void build(int p,int l,int r){
		if(l == r){
			mx[p] = a[l];
			id[p] = l;
			return;
		}
		int mid = (l+r)/2;
		build(p*2,l,mid);
		build(p*2+1,mid+1,r);
		if(mx[p*2]>mx[p*2+1]){
			mx[p] = mx[p*2];
			id[p] = id[p*2];
		}
		else{
			mx[p] = mx[p*2+1];
			id[p] = id[p*2+1];
		}
	}
	void update(int p,int L,int R,int ID,int x){
		if(L == R){
			mx[p] = x;
			return;
		}
		int mid = (L+R)/2;
		if(ID <= mid)update(p*2,L,mid,ID,x);
		else update(p*2+1,mid+1,R,ID,x);
		
		if(mx[p*2]>mx[p*2+1]){
			mx[p] = mx[p*2];
			id[p] = id[p*2];
		}
		else{
			mx[p] = mx[p*2+1];
			id[p] = id[p*2+1];
		}
	}
	node query(int p,int L,int R,int l,int r){
		if(l == L&&R == r){
			return node{id[p],mx[p]};
		}
		int mid = (L+R)/2;
		if(r <= mid){
			return query(p*2,L,mid,l,r);
		}
		else if(l > mid){
			return query(p*2+1,mid+1,R,l,r);
		}
		else{
			node LL = query(p*2,L,mid,l,mid);
			node RR = query(p*2+1,mid+1,R,mid+1,r);
			if(LL.mx > RR.mx){
				return LL;
			}
			else{
				return RR;
			}
		}
	}
}t1,t2;
int main(){
	cin>>n;
	for(int i = 1;i <= n;i++){
		cin>>d[i];
	
	}
	
	for(int i = 1;i <= n;i++){
		cin>>t[i];
		t2.a[i] = 2*d[i]+t[i];
		t1.a[i] = t[i];
	}
	t1.build(1,1,n);
	t2.build(1,1,n);
	for(int i = 1;i <= n;i++){
		node L = {-1,-1},R = {-1,-1};
	//	cout<<i<<endl;
		if(deep > 0){
			L = t1.query(1,1,n,1,deep);
		}
		if(deep < n){
			//cout<<"UES"<<endl;
			R = t2.query(1,1,n,deep+1,n);
			
		}
		//cout<<R.mx-2*d[deep]<<" "<<R.id<<" "<<L.mx<<" "<<L.id<<endl;
		if(R.mx-2*d[deep] >= L.mx){
			ans+=R.mx-2*d[deep];
			t2.update(1,1,n,R.id,-2);
			t1.update(1,1,n,R.id,-2);
			deep = R.id;
		}
		else{
			ans+=L.mx;
			t1.update(1,1,n,L.id,-1);
			t2.update(1,1,n,L.id,-2);
		}
		cout<<ans<<endl;
	} 
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值