我们可以想到一个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. unity 学习记录

    世界第九条约定 缘起 嗯,其实一开始我知道unity是个弄游戏的,也知道好像神庙逃亡,炉石都是出自unity,然后舍友都报了,我也觉得这个东西挺高大上的,所以忍不住自己的双手,报了名,确实,这能学到很 ...

  2. iOS- Swift实现UITableView的常见操作

    1.前言   Swift在这就不多介绍了,想必大家都已皆知. 离Swift面世也过了有一个多月的时间. 在闲暇时间我用Swift实现了UITableView的一些常见操作. 基本都是可以用上的,今天在 ...

  3. 修改QQ各版本的默认保存位置(聊天记录)

    这几天没少折腾windows,都有点烦了,我是那种有强迫症的,只要知道的自己没有做到的会感觉到浑身不爽的因为系统重装了好几次,QQ也没少安装几次,我使用的是TM的QQ(没有 那么多烦人的广告,娱乐组件 ...

  4. hdu3625-Rooms

    题目 有\(n\)个房间,\(n\)个钥匙,每个钥匙随机出现在一个房间里,一个房间里有且仅有一个钥匙.我们现在手上没有钥匙,但我们要搜索所有的房间,所以我们有\(k\)次机会把一个房间炸开.一号房间里 ...

  5. hdu 1688 Sightseeing (最短路径)

    Sightseeing Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  6. Python对文件和文件夹的高级操作模块shutil

    shutil模块提供了许多关于文件和文件夹的高级操作. 特别提供了支持文件复制和删除的功能. # 将文件对象fsrc的内容复制到文件类对象fdst.length(可选参数)是缓冲区大小 shutil. ...

  7. robot framework连接Oracle错误:ORA-12504: TNS:listener was not given the SERVICE_NAME in CONNECT_DATA

    在使用robot framework的关键字Connect to Database Using Custom params连接Oracle数据库: Connect to Database Using ...

  8. PyTorch为何如此高效好用?

    C/C++中 Python 扩展对象的简介 你可能知道可以借助 C/C++扩展 Python,并开发所谓的「扩展」.PyTorch 的所有繁重工作由 C/C++实现,而不是纯 Python.为了定义 ...

  9. BZOJ4311:向量——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4311 你要维护一个向量集合,支持以下操作: 1.插入一个向量(x,y) 2.删除插入的第i个向量 ...

  10. 51NOD 1934:受限制的排列——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1934 听说会笛卡尔树的人这题都秒了啊…… 参考:https://blog ...