poj 2374

dp+线段树,dp是核心,线段树用来优化复杂度,dp过程好像,但是要确定从一个fence边缘向下沿直线走,下一个fence是哪个,最朴素的想法就是从上到下扫描,时间为O(n2),数据量比较大,可能会超时。然后用线段树来优化这个过程,当输入第i个fence的左右点时,1~i-1的fence所覆盖区间已插入到了线段树中(并在所覆盖的区间发记录fence编号)那么此时,求fence(i)的左点l向下会走到哪个fence,可以从线段树的根开始搜索,搜索到l的这条路径上的最大编号,也就是覆盖了点l的区间上的最大编号,从而得到所求编号

#include <iostream>
#include <cstdio>
#include <cmath>
#define max(a,b) ((a)>(b)?(a):(b)) 
#define min(a,b) ((a)<(b)?(a):(b)) 
using namespace std;
const int maxm=(100000+10)*3;
const int maxn=50000+10;
int num[maxm*3];
int n,s,ul,ur,ql,qr;
int f[maxn][2],rloc,next[maxn][2],setv,seg[maxn][2];
void Update(int no,int l,int r)
{
	if(l>=ul&&r<=ur)
	{
		if(setv>num[no]) num[no]=setv;
		return;
	}
	int mid=l+(r-l)/2;
	if(ul<=mid) Update(no*2+1,l,mid);
	if(ur>mid) Update(no*2+2,mid+1,r);
}
void Query(int no,int l,int r)
{
	if(l>=ql&&r<=qr)
	{
		rloc=max(rloc,num[no]);
		return;
	}
	int mid=l+(r-l)/2;
	if(ql<=mid) Query(no*2+1,l,mid);
	if(qr>mid) Query(no*2+2,mid+1,r);
	rloc=max(rloc,num[no]);
}
int main()
{
	scanf("%d%d",&n,&s);
	int i;
	memset(num,0,sizeof(num));//初始化线段树 
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&ul,&ur);
		seg[i][0]=ul;seg[i][1]=ur;
		rloc=-1;ql=qr=ul;
		Query(0,-100000,100000);
		next[i][0]=rloc;
		rloc=-1;ql=qr=ur;
		Query(0,-100000,100000);
		next[i][1]=rloc;
		setv=i;
		Update(0,-100000,100000);
	}
	f[0][0]=f[0][1]=0;
	seg[0][0]=seg[0][1]=0;
	for(i=1;i<=n;i++)//dp过程
	{
		int j1=next[i][0],j2=next[i][1];
		f[i][0]=min((f[j1][0]+abs(seg[i][0]-seg[j1][0])),(f[j1][1]+abs(seg[i][0]-seg[j1][1])));
		f[i][1]=min(f[j2][0]+abs(seg[i][1]-seg[j2][0]),f[j2][1]+abs(seg[i][1]-seg[j2][1]));
	}
	int ans=min(f[n][0]+abs(s-seg[n][0]),f[n][1]+abs(s-seg[n][1]));
	printf("%d\n",ans);
	return 0;
}


原文地址:https://www.cnblogs.com/lj030/p/3002209.html