我们可以想到一个dp方程:f[i][0]表示当前在i个栅栏的左端点,f[i][1]表示在右端点。

分两种情况:

第一种:假设现在要更新线段gh的左端点g,而它下来的路径被ef挡住了,那么必定是有ef来更新g。

为什么呢?因为其它点走到g必定要下落,比如说d到g,就相当于d到f再到g。

第二种:假设到ab的路径上没有东西挡着,那就可以直接从源点走过去再直接下落。

按照从上到下的顺序插入线段,线段树就是找当前的某个点被哪条id最大(也就是最低的)线段所覆盖。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<ctime>
#include<queue>
#include<algorithm>
using namespace std; const int N=**,INF=(int)1e9;
int n,st,pl,tl,r[N],f[N][];
struct node{
int d,id,tmp;
}p[N];
struct nd{
int x1,x2;
}a[N];
struct trnode{
int l,r,lc,rc,id,lazy;
}t[*N]; bool cmp_d(node x,node y){return x.d<y.d;}
int myabs(int x){return x> ? x:-x;}
int minn(int x,int y){return x<y ? x:y;}
int maxx(int x,int y){return x>y ? x:y;} int bt(int l,int r)
{
int x=++tl;
t[x].l=l;t[x].r=r;
t[x].lc=t[x].rc=;
t[x].id=INF;t[x].lazy=INF;
if(l<r)
{
int mid=(l+r)/;
t[x].lc=bt(l,mid);
t[x].rc=bt(mid+,r);
}
return x;
} void upd(int x)
{
if(t[x].lazy==INF) return ;
int id=t[x].lazy,lc=t[x].lc,rc=t[x].rc;
t[x].lazy=INF;
t[x].id=minn(t[x].id,id);
if(lc) t[lc].lazy=minn(t[lc].lazy,id);
if(rc) t[rc].lazy=minn(t[rc].lazy,id);
} void change(int x,int l,int r,int id)
{
upd(x);
if(t[x].l==l && t[x].r==r)
{
t[x].lazy=minn(t[x].lazy,id);
upd(x);
return ;
}
int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/;
if(r<=mid) change(lc,l,r,id);
else if(l>mid) change(rc,l,r,id);
else
{
change(lc,l,mid,id);
change(rc,mid+,r,id);
}
} int query(int x,int p)
{
upd(x);
if(t[x].l==t[x].r) return t[x].id;
int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/;
if(p<=mid) return query(lc,p);
else return query(rc,p);
} int main()
{
// freopen("a.in","r",stdin);
// freopen("me.out","w",stdout);
freopen("obstacle.in","r",stdin);
freopen("obstacle.out","w",stdout);
scanf("%d%d",&n,&st);
int x,ed;ed=;pl=;tl=;
p[++pl].d=st;p[pl].id=n+;
p[++pl].d=ed;p[pl].id=n+;
for(int i=;i<=n;i++)
{
scanf("%d%d",&a[i].x1,&a[i].x2);
if(a[i].x1>a[i].x2) swap(a[i].x1,a[i].x2);
p[++pl].d=a[i].x1;p[pl].id=i;p[pl].tmp=;
p[++pl].d=a[i].x2;p[pl].id=i;p[pl].tmp=;
}
sort(p+,p++pl,cmp_d);
int mx=;p[].d=INF;
for(int i=;i<=pl;i++)
{
if(p[i].d!=p[i-].d) mx++,r[mx]=p[i].d;
if(p[i].id==n+) st=mx;
else if(p[i].id==n+) ed=mx;
else
{
if(p[i].tmp==) a[p[i].id].x1=mx;
else a[p[i].id].x2=mx;
}
}
bt(,mx);
change(,st,st,n+);
a[n+].x1=a[n+].x2=st;
f[n+][]=f[n+][]=;
a[].x1=a[].x2=ed;
for(int i=n;i>=;i--)
{
x=query(,a[i].x1);
if(x<INF) f[i][]=minn(f[x][]+myabs(r[a[x].x1]-r[a[i].x1]),f[x][]+myabs(r[a[x].x2]-r[a[i].x1]));
else f[i][]=myabs(r[st]-r[a[i].x1]);
x=query(,a[i].x2);
if(x<INF) f[i][]=minn(f[x][]+myabs(r[a[x].x1]-r[a[i].x2]),f[x][]+myabs(r[a[x].x2]-r[a[i].x2]));
else f[i][]=myabs(r[st]-r[a[i].x2]);
change(,a[i].x1,a[i].x2,i);
}
printf("%d\n",f[][]);
return ;
}

【bzoj3387-跨栏训练】线段树+dp的更多相关文章

  1. Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)

    [题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...

  2. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  3. CodeForces–833B--The Bakery(线段树&&DP)

    B. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  4. lightoj1085 线段树+dp

    //Accepted 7552 KB 844 ms //dp[i]=sum(dp[j])+1 j<i && a[j]<a[i] //可以用线段树求所用小于a[i]的dp[j ...

  5. [CF 474E] Pillars (线段树+dp)

    题目链接:http://codeforces.com/contest/474/problem/F 意思是给你两个数n和d,下面给你n座山的高度. 一个人任意选择一座山作为起始点,向右跳,但是只能跳到高 ...

  6. HDU-3872 Dragon Ball 线段树+DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3872 题意:有n个龙珠按顺序放在一列,每个龙珠有一个type和一个权值,要求你把这n个龙珠分成k个段, ...

  7. HDU4521+线段树+dp

    题意:在一个序列中找出最长的某个序列.找出的序列满足题中的条件. 关键:对于 第 i 个位置上的数,要知道与之相隔至少d的位置上的数的大小.可以利用线段树进行统计,查询.更新的时候利用dp的思想. / ...

  8. Codeforces Round #343 (Div. 2) D - Babaei and Birthday Cake 线段树+DP

    题意:做蛋糕,给出N个半径,和高的圆柱,要求后面的体积比前面大的可以堆在前一个的上面,求最大的体积和. 思路:首先离散化蛋糕体积,以蛋糕数量建树建树,每个节点维护最大值,也就是假如节点i放在最上层情况 ...

  9. Special Subsequence(离散化线段树+dp)

    Special Subsequence Time Limit: 5 Seconds      Memory Limit: 32768 KB There a sequence S with n inte ...

随机推荐

  1. 用纯css改变下拉列表select框的默认样式(转)

    用纯css改变下拉列表select框的默认样式 分享到 分类 JS学习   关键字 前端   发布 kris  2015-04-01 注意 转载须保留原文链接,译文链接,作者译者等信息.     在这 ...

  2. 3ds Max学习日记(三)

      今天把第三章搞完了,学的是样条线(splines)建模的一些操作.不过实习又有新任务了,得去研究一下如何将单张图片转化为三维模型(我擦,这神马操作),所以可能没有那么多时间愉快地与3ds max玩 ...

  3. 工具函数:cookie的添加、获取、删除

    cookie是浏览器存储的命名数据,作用是保存用户的信息,这样我们就可以用这些信息来做一些事了,但是cookie容量很小,只有4kb. 下面是我总结的cookie的添加.获取.删除的函数: cooki ...

  4. 播放MP3

    播放背景音乐 上文来自:http://blog.csdn.net/henulwj/article/details/8977738 using System; using System.Collecti ...

  5. 整理下本周工作中遇到的疑问;uid/euid/suid;docker镜像管理

    1.系统中的父子进程关系,以及docker是如何处理的这种父子进程关系,线上问题发现,子进程长时间得不到退出. 2.调用system系统调用发生了啥事情,发现大量的页表拷贝. 3.通过shell命令通 ...

  6. perf中branch-filter到底是干嘛的?

    ./arch/x86/events/intel/core.c:2161:            data.br_stack = &cpuc->lbr_stack;./arch/x86/e ...

  7. 【bzoj4196】[Noi2015]软件包管理器 树链剖分+线段树

    题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...

  8. hdu 3367 Pseudoforest (最小生成树)

    Pseudoforest Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  9. hdu 2050 折线分割平面 (递推)

    折线分割平面 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  10. 如何正确实现Page接口分页,用PageImpl 自定义分页

    /** * Constructor of {@code PageImpl}. * * @param content the content of this page, must not be {@li ...