POJ 2374/bzoj 3387: [Usaco2004 Dec]Fence Obstacle Course栅栏行动

真是想打人 有一点点看错题意...(捂脸)

可以把问题换个角度思考,从某线段端点掉下来会到哪个线段上。

在这个角度下 可以用DP 设f[i][0],f[i][1]分别表示第i条线段的左端点和右端点到最终源点的最小距离

如果暴力求的话 就是O(N^2) 但是 前面都这样说了 很明显就是可以用线段树来logN求

从第一条线段开始 单点询问 然后区间修改 对了 记得对于每个端点加上一个值(就是去除负数嘛)

然后就没什么了


对了 很好奇网上面别人代码的准确性 一开始想拿来对拍的 发现好多个跑出来的数据我对了他们错了QAQ

比如

4 -7
-40 53
6 58
56 95
42 88
是73对吧 有一个居然输出123。。

#include
#include
#include
#include
#include
#include
#include
#define me(a,x) memset(a,x,sizeof a)
#define cp(a,x) memcpy(a,x,sizeof a)
using namespace std;
typedef long long LL;
const int N=50010,inf=1e9,add=100005;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct node{int x,y;}a[N];
int f[N][2],mx[add<<3];
void change(int x,int l,int r,int ql,int qr,int u)
{
	if(l==ql && r==qr){mx[x]=u; return;}
	int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
	if(mx[x])mx[lc]=mx[rc]=mx[x],mx[x]=0;
	if(qr<=mid)change(lc,l,mid,ql,qr,u);
	else if(ql>mid)change(rc,mid+1,r,ql,qr,u);
	else
	{
		change(lc,l,mid,ql,mid,u);
		change(rc,mid+1,r,mid+1,qr,u);
	}
}
int query(int x,int l,int r,int u)
{
	if(l==r)return mx[x];
	int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
	if(mx[x])mx[lc]=mx[rc]=mx[x],mx[x]=0;
	if(u<=mid)return query(lc,l,mid,u);
	return query(rc,mid+1,r,u);
}
int main()
{
	int i,n,s,x,y,lx,ly;
	n=read(),s=read()+add; lx=ly=a[0].x=a[0].y=add;
	for(i=1;i<=n+1;i++)
	{
		if(i<=n)a[i].x=read()+add,a[i].y=read()+add;
		else a[i].x=a[i].y=s;
		lx=min(lx,a[i].x),ly=max(ly,a[i].y);
	}
	for(i=1;i<=n+1;i++)
	{
		x=query(1,lx,ly,a[i].x),y=query(1,lx,ly,a[i].y);
		f[i][0]=min(f[x][0]+abs(a[i].x-a[x].x),f[x][1]+abs(a[i].x-a[x].y));
		f[i][1]=min(f[y][0]+abs(a[i].y-a[y].x),f[y][1]+abs(a[i].y-a[y].y));
		change(1,lx,ly,a[i].x,a[i].y,i);
	}
	printf("%d\n",f[n+1][0]);
    return 0;
}


你可能感兴趣的:(poj,usaco,bzoj,线段树)