我们可以想到一个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. android平台蓝牙编程(转)

    http://blog.csdn.net/pwei007/article/details/6015907 Android平台支持蓝牙网络协议栈,实现蓝牙设备之间数据的无线传输. 本文档描述了怎样利用a ...

  2. Java常用类之File类

    File 类: 1. java.io.File 类代表系统文件名(路径名.文件名); 2. File 类常见的构造方法: 2.1. File(String pathname):通过将给定路径名字符串转 ...

  3. 后端设置cookie写不到前端页面

    javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie("id",session.getId()); co ...

  4. ArrayList遍历(JAVA)

    假如有个ArrayList变量如下: ArrayList<String> list = new ArrayList<String>(); list.add("arra ...

  5. lol人物模型提取(九)——终章

      之前顺丰来人拍照取证了一下,又和卖家协商了一下,最后顺风只打算赔偿我23块钱的顺丰邮寄卡,就是当你寄货物的时候可以用这卡来抵邮钱.想想也没多少钱,对方也不同意微信或支付宝转账给我,索性不让顺丰公司 ...

  6. sublime Text3 设置用新标签页打开新的文件

    今天用sublime Text3 打开项目文件,发现单击文件就可以打开,但是有一个问题:每次打开新文件就会覆盖当前的标签页,无法在新的标签页打开.于是在网上查了一下. 网上有人说在Preference ...

  7. Python自定义包在linux服务器导入错误的解决办法

    在本地机器上跑python代码,自己定义的文件进行导包运行是没有问题,但是放到linux服务器上的时候就会提示 ImportError:No module named xxxx(要导入的文件包名) 在 ...

  8. Matlab 函数ndims简介,flipdim简介

    ndims是matlab中求一个数组维数的函数. 调用格式: n=ndims(A) 将A的维数返回给变量n.n>=2 n=ndims(A)与n=length(size(A))是等价的 MATLA ...

  9. bzoj2676 Contra

    题意: 给定N,R,Q,S 有N个关卡,初始有Q条命,且任意时刻最多只能有Q条命 每通过一个关卡,会得到u分和1条命,其中u=min(最近一次连续通过的关数,R) 若没有通过这个关卡,将失去一条命,并 ...

  10. BZOJ5301:[CQOI2018]异或序列——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5301 https://www.luogu.org/problemnew/show/P4462 已知 ...