POJ 3171 Cleaning Shifts 线段树优化DP

题面大意:
有N个线段,每个线段可以覆盖一段区间T1-T2 花费为S,求选出几个线段使得其完全覆盖M 到E 这一区间 并要求花费最少。

复杂度要求 nlog(E)。

这道题数据比较水,不要求离散化。考虑DP f[T2] = min(f[x]) +c {T1-1<=x<T2}

整个f数列可以用一颗线段树维护,维护最小值

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;

const int maxn = 1e5+100;

struct node
{
	int x,y;
	long long z;
}T[maxn*4];

bool cmp(node a,node b)
{
	return a.y < b.y; 
}

int n,L,R,x,y,z;
long long f[maxn],mi[maxn*4];

void build(int rt,int l,int r)
{
	if(l==r)
	{
		mi[rt]=f[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	mi[rt]=min(mi[ls],mi[rs]);
}

void update(int rt,int l,int r,int x,long long val)
{
	if(l==r)
	{
		mi[rt]=val;
		return ;
	}
	int mid=(l+r)>>1;
	if(x<=mid) update(ls,l,mid,x,val);
	else update(rs,mid+1,r,x,val);
	mi[rt]=min(mi[ls],mi[rs]);
}
long long query(int rt,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
	{
		return mi[rt];
	}
	int mid=(l+r)>>1;
	long long res=1e15;
	if(L<=mid) res = min(res,query(ls,l,mid,L,R));
	if(R>mid) res = min(res,query(rs,mid+1,r,L,R));
	return res; 
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>L>>R;
	L+=2;R+=2;
	memset(f,0x3f,sizeof(f));
	memset(mi,0x3f,sizeof(mi));
	for(int i=1;i<=n;i++)
	{
		cin>>T[i].x>>T[i].y>>T[i].z;
		T[i].x+=2;T[i].y+=2;
	}
	sort(T+1,T+1+n,cmp);
	f[L-1]=0;
	build(1,1,R);
	for(int i=1;i<=n;i++)
	{
		if(T[i].y>R) T[i].y = R;
		if(T[i].x<L) T[i].x = L;
		long long res = query(1,1,R,T[i].x-1,T[i].y-1);
		f[T[i].y] = min(f[T[i].y],res+T[i].z);
		update(1,1,R,T[i].y,f[T[i].y]);
	}
	if(f[R]>1e9) cout<<"-1"<<endl;
	else cout<<f[R]<<endl;
	return 0;
}
/*
3 0 4
0 2 3
3 4 2
0 0 1
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值