真是想打人 有一点点看错题意...(捂脸)
可以把问题换个角度思考,从某线段端点掉下来会到哪个线段上。
在这个角度下 可以用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<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#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;
}