POJ 2374 Fence Obstacle Course 线段树优化DP

原创 2016年08月29日 09:54:24

时空隧道


题目大意:
给出一些篱笆,编号为1~n,1号篱笆在最下面,n号篱笆在最上面,给出起点s的坐标,要求牛从起点出发,到达到达n号篱笆下面的地上的0点,求出最小横向路径


分析:
dp方程比较好想,大概就是没一个篱笆可以更新它下面的最近的一个可以直达的篱笆,还是看代码吧:

    f[1][0]=labs(s-a[1]),f[1][1]=labs(b[1]-s);
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++)
            if(a[i]>=a[j]&&a[i]<=b[j]){
                f[j][0]=min(f[j][0],f[i][0]+labs(a[j]-a[i]));
                f[j][1]=min(f[j][1],f[i][0]+labs(a[i]-b[j]));
                break;
            }
        for(int j=i+1;j<=n;j++)
            if(b[i]>=a[j]&&b[i]<=b[j]){
                f[j][0]=min(f[j][0],f[i][1]+labs(b[i]-a[j]));
                f[j][1]=min(f[j][1],f[i][1]+labs(b[j]-b[i]));
                break;
            }
    }

然后我们发现这是O(n^2)的转移,n<=5W,挂了
然后我们发现,对于每个i所对应的j可以用线段树来维护,大概可以简化为区间覆盖问题:倒着插入区间,更新区间id,查询每个篱笆的左右端点被哪个id覆盖


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define ZERO 100005
#define int long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=50000+5,maxm=200000+5;
int n,s,a[maxn],b[maxn],f[maxn][2],MAX,MIN;
struct Tree{
    int l,r,id;
}tree[maxm*4]; 
struct M{
    int A,B;
}S[maxn];
inline void build(int l,int r,int tr){
    tree[tr].l=l,tree[tr].r=r,tree[tr].id=0;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(l,mid,tr<<1),build(mid+1,r,tr<<1|1);
} 
inline void change(int l,int r,int id,int tr){
    if(tree[tr].l==l&&tree[tr].r==r){
        tree[tr].id=id;
        return; 
    }
    int mid=(tree[tr].l+tree[tr].r)>>1;
    if(tree[tr].id!=-1){
        tree[tr<<1].id=tree[tr].id;
        tree[tr<<1|1].id=tree[tr].id;
    }
    if(r<=mid)
        change(l,r,id,tr<<1);
    else if(l>mid)
        change(l,r,id,tr<<1|1);
    else 
        change(l,mid,id,tr<<1),change(mid+1,r,id,tr<<1|1);
    if(tree[tr<<1].id!=tree[tr<<1|1].id||tree[tr<<1].id==-1||tree[tr<<1|1].id==-1)
        tree[tr].id=-1;
}
inline int query(int pos,int tr){
    if(tree[tr].l==tree[tr].r||(tree[tr].l<=pos&&tree[tr].r>=pos&&tree[tr].id!=-1))
        return tree[tr].id;
    int mid=(tree[tr].l+tree[tr].r)>>1;
    if(tree[tr].id!=-1){
        tree[tr<<1].id=tree[tr].id;
        tree[tr<<1|1].id=tree[tr].id;
    }
    if(pos>mid)
        return query(pos,tr<<1|1);
    else
        return query(pos,tr<<1);
}
signed main(void){
    scanf("%lld%lld",&n,&s),MAX=-inf,MIN=inf;
    memset(f,inf,sizeof(f));
    for(int i=n;i>=1;i--)
        scanf("%lld%lld",&a[i],&b[i]),MAX=max(MAX,b[i]),MIN=min(a[i],MIN);
    f[1][0]=labs(s-a[1]),f[1][1]=labs(b[1]-s);
    build(ZERO+MIN,MAX+ZERO,1);
    for(int i=n;i>=1;i--)
        S[i].A=query(a[i]+ZERO,1),S[i].B=query(b[i]+ZERO,1),change(a[i]+ZERO,b[i]+ZERO,i,1);
    for(int i=1;i<n;i++){
        int j=S[i].A;
        if(j!=0)
            f[j][0]=min(f[j][0],f[i][0]+labs(a[j]-a[i])),f[j][1]=min(f[j][1],f[i][0]+labs(a[i]-b[j]));
        j=S[i].B;
        if(j!=0)
            f[j][0]=min(f[j][0],f[i][1]+labs(b[i]-a[j])),f[j][1]=min(f[j][1],f[i][1]+labs(b[j]-b[i]));
    }
    int ans=min(f[n][0]+labs(a[n]),f[n][1]+labs(b[n]));
    for(int i=1;i<n;i++){
        if(S[i].A==0)
            ans=min(f[i][0]+labs(a[i]),ans);
        if(S[i].B==0)
            ans=min(ans,f[i][1]+labs(b[i]));
    }
    cout<<ans<<endl;
    return 0;
}

by >_< neighthorn

版权声明:转载请注明出处---by 小雪刺

poj1155 TELE(树形dp+背包)

TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4344   Accepted:...
  • d_x_d
  • d_x_d
  • 2015年11月16日 20:06
  • 1512

POJ 3734 Blocks(矩阵优化+DP)

题目链接:点击打开链接 题意:个n个方块涂色, 只能涂红黄蓝绿四种颜色,求最终红色和绿色都为偶数的方案数。 该题我们可以想到一个递推式 。   设a[i]表示到第i个方块为止红绿是偶数的方案数, ...
  • weizhuwyzc000
  • weizhuwyzc000
  • 2016年01月12日 18:35
  • 1075

树形dp入门之poj 2342

题目:poj2342Anniversary party 题意:话说一个公司的一些然要去参加一个party,每个人有一个愉悦值,而如果某个人的直接上司在场的话会非常扫兴,所以避免这样的安排,问...
  • y990041769
  • y990041769
  • 2014年07月23日 12:57
  • 3806

[线段树]POJ 2374 Fence Obstacle Course

这道题目先抛开时间效率来分析。 我们可以开一个一维数组w[],数组下标就是区间的端点值,cow刚开始在w[s]处。碰到一个区间后,我们看这个区间会覆盖多少个值(实际就是到前面区间的端点所花的步数),...
  • zhaofukai
  • zhaofukai
  • 2012年09月05日 00:48
  • 1294

POJ2374 Fence Obstacle Course——线段树+动态规划

初次看到这道题,明显的动态规划。但是,朴素的转移方程的时间复杂度是O(n^2)的,对于n 注意到这题有个隐含的条件:从每个栅栏往下走只能走到最多两个固定的栅栏上面:即向左拐、向右拐只能到确定的栅栏上...
  • This_Poet
  • This_Poet
  • 2011年08月29日 02:00
  • 1117

POJ 2374 Fence Obstacle Course

Description Farmer John has constructed an obstacle course for the cows' enjoyment. The course ...
  • jtjy568805874
  • jtjy568805874
  • 2015年08月09日 15:31
  • 288

POJ 2374 线段树建图+Dijkstra

题意: 思路: 线段树+Dijkstra(要堆优化的)线段树要支持打标记 一个栅栏 拆成两个点 :左和右 新加一个栅栏的时候 看看左端点有没有被覆盖过 如果有的话 就分别从覆盖...
  • qq_31785871
  • qq_31785871
  • 2016年10月31日 15:02
  • 518

poj 2374 求横向距离和最小 线段树 + 动态规划

题目的意思就是有一群牛它们懒得动,不会跳跃越过篱笆,现在它们要从S点走到最下面的谷仓*,它们往下走碰到篱笆就选择往左或往右沿着篱笆走,走到篱笆端点的时候在往下走碰到篱笆再选择往左或往右沿着篱笆走,如此...
  • xiaoxiaoluo
  • xiaoxiaoluo
  • 2012年03月13日 02:22
  • 1509

BZOJ3387: [Usaco2004 Dec]Fence Obstacle Course栅栏行动

题目大意:给定一个初始点和n个与x轴平行的y轴坐标互不相同的栅栏,问水平距离至少移动多少能使得从该初始点回到原点且不从中间跨越任何一条栅栏 首先可以确定,最终行进的路线一定可以等价于在几个栅...
  • commonc
  • commonc
  • 2016年08月22日 08:30
  • 448

BZOJ3387 [USACO2004 Dec] Fence Obstacle Course栅栏行动

[Solution] Simply modify some important positions by
  • laekov
  • laekov
  • 2014年08月17日 12:52
  • 792
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 2374 Fence Obstacle Course 线段树优化DP
举报原因:
原因补充:

(最多只允许输入30个字)