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; }