poj2374 Fence Obstacle Course(DP)(线段树)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/82932474

题目

poj2374 Fence Obstacle Course

题解

线段树优化DP
设f[i][0/1]表示在通过第i条栅栏后,处于栅栏左边/右边的最小路径长。
因为奶牛是直线下来的,所以最优方案当然是从上一个栅栏的这个位置下来。由于有栅栏的影响,奶牛们不能顺利的下来,此时到达这个位置的最优策略要么是从前面那个栅栏的左端点过来,要么从右端点过来。所以有f[i][0]=\min(f[j][0]+abs(l[i]-l[j]),f[j][1]+abs(l[i]-r[j])f[i][1]=\min(f[j][0]+abs(r[i]-l[j]),f[j][1]+abs(r[i]-r[j]))
其中的j就是上一个挡住了这个位置的栅栏。我们可以用线段树来维护这个栅栏的编号。当栅栏(l[i],r[i]),出现后,我们把线段树上(l[i],r[i])这段区间改成i,表示这个位置是栅栏i阻挡了。对于后面的栅栏,修改时直接覆盖前面的信息即可。我们只要实现一个改段求点的线段树即可。
特别的,线段树初始值为0。一个位置如果得到的j=0,那么说明它前面没有栅栏,它可以直接从s过来,路径=abs(s-p)。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rt 1,1,tot
using namespace std;
const int maxn=50010,maxtr=maxn*2*4;

int hh[maxtr],la[maxtr];

void update(int x)
{
    if(la[x]==-1) return ;
    int lc=x<<1,rc=lc|1;
    hh[lc]=hh[rc]=la[x];
    la[lc]=la[rc]=la[x];
    la[x]=-1;
}

void change(int x,int xl,int xr,int l,int r,int c)
{
    if(xl==l && xr==r)
    {
        hh[x]=la[x]=c;
        return ;
    }
    int mid=xl+xr>>1;
    int lc=x<<1,rc=lc|1;
    update(x);
    if(r<=mid) change(lc,xl,mid,l,r,c);
    else if(mid<l) change(rc,mid+1,xr,l,r,c);
    else change(lc,xl,mid,l,mid,c),change(rc,mid+1,xr,mid+1,r,c);
}

int ask(int x,int xl,int xr,int p)
{
    if(xl==xr)
    {
        return hh[x];
    }
    int mid=xl+xr>>1;
    int lc=x<<1,rc=lc|1;
    update(x);
    if(p<=mid) return ask(lc,xl,mid,p);
    else return ask(rc,mid+1,xr,p);
}

int l[maxn],r[maxn];
int a[maxn*2];int tot=0;
int ul[maxn],ur[maxn];
int f[maxn][2];

int main()
{
    int n,s;
    scanf("%d%d",&n,&s);
    for(int i=n;i>=1;i--)
    {
        scanf("%d%d",&l[i],&r[i]);
        a[++tot]=l[i];a[++tot]=r[i];
    }
    a[++tot]=0;a[++tot]=s;
    sort(a+1,a+tot+1);tot=unique(a+1,a+tot+1)-(a+1);
    for(int i=1;i<=n;i++) ul[i]=lower_bound(a+1,a+tot+1,l[i])-a,ur[i]=lower_bound(a+1,a+tot+1,r[i])-a;
    
    for(int i=1;i<=n;i++)
    {
        int fl=ask(rt,ul[i]),fr=ask(rt,ur[i]);
        if(fl==0) f[i][0]=abs(s-l[i]);
        else f[i][0]=min(f[fl][0]+abs(l[fl]-l[i]),f[fl][1]+abs(r[fl]-l[i]));
        if(fr==0) f[i][1]=abs(s-r[i]);
        else f[i][1]=min(f[fr][0]+abs(l[fr]-r[i]),f[fr][1]+abs(r[fr]-r[i]));
        change(rt,ul[i],ur[i],i);
    }
    int e=lower_bound(a+1,a+tot+1,0)-a;
    int ff=ask(rt,e);
    if(ff==0) printf("%d\n",abs(s));
    else printf("%d\n",min(f[ff][0]+abs(l[ff]),f[ff][1]+abs(r[ff])));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/82932474