天梯L3 17 森森快递 贪心+线段树

L3-017. 森森快递

时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
俞勇(上海交通大学)

森森开了一家快递公司,叫森森快递。因为公司刚刚开张,所以业务路线很简单,可以认为是一条直线上的N个城市,这些城市从左到右依次从0到(N-1)编号。由于道路限制,第i号城市(i=0, ..., N-2)与第(i+1)号城市中间往返的运输货物重量在同一时刻不能超过 Ci公斤。

公司开张后很快接到了Q张订单,其中第j张订单描述了某些指定的货物要从Sj号城市运输到Tj号城市。这里我们简单地假设所有货物都有无限货源,森森会不定时地挑选其中一部分货物进行运输。安全起见,这些货物不会在中途卸货。

为了让公司整体效益更佳,森森想知道如何安排订单的运输,能使得运输的货物重量最大且符合道路的限制?要注意的是,发货时间有可能是任何时刻,所以我们安排订单的时候,必须保证共用同一条道路的所有货车的总重量不超载。例如我们安排1号城市到4号城市以及2号城市到4号城市两张订单的运输,则这两张订单的运输同时受2-3以及3-4两条道路的限制,因为两张订单的货物可能会同时在这些道路上运输。

输入格式:

输入在第一行给出两个正整数N和Q(2 <= N <= 105, 1 <= Q <= 105),表示总共的城市数以及订单数量。

第二行给出(N-1)个数,顺次表示相邻两城市间的道路允许的最大运货重量Ci(i=0, ..., N-2)。题目保证每个Ci是不超过231的非负整数。

接下来Q行,每行给出一张订单的起始及终止运输城市编号。题目保证所有编号合法,并且不存在起点和终点重合的情况。

输出格式:

在一行中输出可运输货物的最大重量。

输入样例:
10 6
0 7 8 5 2 3 1 9 10
0 9
1 8
2 7
6 3
4 5
4 2
输出样例:
7
样例提示:我们选择执行最后两张订单,即把5公斤货从城市4运到城市2,并且把2公斤货从城市4运到城市5,就可以得到最大运输量7公斤。

题意:  题意很恶心人  ,  就是给你 n 个点  n-1  个段  和每个段的负重  你要求出 这些段 在任意时刻的最大负重量。

思路:  类似于 求 最大不相交覆盖。  但是这里并不是真的不能覆盖 ,只是需要贪心的去求  给出的m  个区间的 中的最小值

如果最小值等于  0  那么就一定不能再向这一段区间上加 重量,   所以 这个题的关键是   1 贪心的枚举给出的区间 2  快速的求出区间的最小值  (当然用线段树比较快 )

代码: 

#include<bits/stdc++.h>
#define N 100005

using namespace std;

typedef long long ll;

struct node
{
	int l,r;
	ll val;
	int lazy;
	ll tag;
}tree[N<<2];

ll dis[N];

struct node1
{
	int l,r;
}reg[N];

int n,m;

bool cmp(node1 a,node1 b)
{
	return a.r<b.r;
}

void push_up(int i)
{
	tree[i].val=min(tree[i<<1].val,tree[i<<1|1].val);
	return ;
}

void push_down(int i)
{
	tree[i].lazy=0;
	tree[i<<1].lazy=tree[i<<1|1].lazy=1;
	ll tag=tree[i].tag;
	tree[i].tag=0;
	tree[i<<1].tag+=tag;
	tree[i<<1|1].tag+=tag;
	tree[i<<1].val+=tag;
	tree[i<<1|1].val+=tag;
	return ;
}

void build(int i,int l,int r)
{
	tree[i].lazy=0;
	tree[i].tag=0;
	tree[i].l=l;  tree[i].r=r;
	tree[i].val=0;
	if(l==r)
	{
		tree[i].val=dis[l];
		return ;
	}
	
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	push_up(i);
	return ;
}

ll query(int i,int l,int r)
{
	if(tree[i].l==l&&tree[i].r==r)
	{
		return tree[i].val;
	}
	
	if(tree[i].lazy) push_down(i);
	push_up(i);
	
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)
	{
		return query(i<<1,l,r);
	}
	else if(l>mid)
	{
		return query(i<<1|1,l,r);
	}
	else
	{
		return min( query(i<<1,l,mid) ,query(i<<1|1,mid+1,r ) );
	}
}

void update(int i,int l,int r,int num)
{
	if(tree[i].l==l&&tree[i].r==r)
	{
		tree[i].val+=num;
		if(l!=r)
		{
			tree[i].lazy=1;
			tree[i].tag+=num;
		}
		return ;
	}
	if(tree[i].lazy) push_down(i);
	
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)
	{
		update(i<<1,l,r,num);
	}
	else if(l>mid)
	{
		update(i<<1|1,l,r,num);
	}
	else
	{
		update(i<<1,l,mid,num);
		update(i<<1|1,mid+1,r,num);
	}
	push_up(i);
	
	//printf("%d %d %d %lld \n",i,tree[i].l,tree[i].r,tree[i].val);
	
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<n;i++) scanf("%lld",&dis[i]);
	build(1,1,n-1);
	
	for(int i=0;i<m;i++)
	{
		cin>>reg[i].l>>reg[i].r;
		if(reg[i].l>reg[i].r) swap(reg[i].l,reg[i].r);
	}
	
	sort(reg,reg+m,cmp);
	/*
	for(int i=0;i<m;i++) cout<<reg[i].l<<" "<<reg[i].r<<endl;
	*/
	ll ans=0;
	for(int i=0;i<m;i++)
	{
		ll num=query(1,reg[i].l+1,reg[i].r);
		
		//printf(" %d %d  num : %lld\n",reg[i].l+1,reg[i].r,num);
		
		if(num>0){
			ans+=num;
			update(1,reg[i].l+1,reg[i].r,-num);
		}
	}
	cout<<ans<<endl;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值