[JZOJ5049] 腐女的生日

来源:互联网 发布:php接口压力测试工具 编辑:程序博客网 时间:2024/04/30 19:17

Description

腐女要过生日了,pty 想给腐女送礼物,但是腐女所在的教室离pty 的教室太远了,于是pty就拜托会动归和A星的djy帮忙送礼物。djy在学校建立了一个平面直角坐标系,他站在了(0,0)点,腐女在(x0,y0)点,djy每次只能往上下左右四个方向移动一步,中间有n栋矩形教学楼,每个教学楼给出两个对角的坐标,并且保证每栋教学楼的周围区域(如图所示)不会有别的教学楼,即djy可以绕一个教学楼走不会碰到任何障碍,现在djy 想知道从起点到终点不碰到任何教学楼,最短需要多少步。
保证每个矩形都不相交,且一个矩形的周围区域不会有别的矩形。
保证所有的y坐标在[-10^6,10^6]
所有的x坐标在[0,10^6]
70%的数据保证:n<=1000
100%的数据保证:n<=10^5

Solution

这题根据经验,我一开始想的是最短路。
对于每个矩形,显然只有左边界上下的点在向外左上左下一个点是有用的。
将这两个点作为关键点。

并且我们发现,除非有一个矩阵锁住起点(就是横坐标为0),一定不可能向左走的。

事实证明并没有这种数据,有的话特判一下就好。

对于当前到达的一个点,观察发现,上下的所有矩阵都不能阻挡它,只有它右边第一个上比它高下比它低的矩阵能影响。

那么这个点和那个矩阵的关键点连边,递归下去。
碰到终点直接连。

然后出来是一个DAG,直接跑拓扑序就好。
但是连边最坏是N2
所以我的是水法,然而数据比较辣鸡,让我过了。

正解是扫描线。
线段树维护一个扫描线,记录起点到扫描线上每个点的距离,用关于纵坐标一次函数表示,向右更新时直接区间操作一次函数的系数和常数项即可。

Code

我的是最短路

#include <cstdio>#include <cstdlib>#include <algorithm>#include <iostream>#include <cstring>#include <cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)#define N 500005using namespace std;int n,m,n1,nt[4*N],dt[4*N],fs[N],pr[4*N],xl,yl,d[2*N],dis[2*N],st,ed,b1[N],ds[2*N],rd[2*N];bool bz[2*N];struct node{    int x,hi,lw;}z[N];void spfa(){    memset(dis,107,sizeof(dis));    memset(bz,0,sizeof(bz));    dis[st]=0;    bz[st]=1;d[1]=st;    int l=0,r=1;    while(l<r)    {        l++;        int l1=l%(2*N);        int p=d[l1];        for(int i=fs[p];i;i=nt[i])        {            int q=dt[i];            rd[q]--;            if(dis[q]>dis[p]+pr[i]&&dis[p]+pr[i]<dis[ed]) dis[q]=dis[p]+pr[i];             if(!bz[q]&&rd[q]==0)            {                bz[q]=1;                r++;                d[r%(2*N)]=q;            }        }    }}void link(int p,int q,int v){    nt[++m]=fs[p];    fs[p]=m;    rd[q]++;    dt[m]=q;    pr[m]=v;}bool cmp(node x,node y){    return (x.x<y.x)||(x.x==y.x&&x.hi==yl)||(x.x==y.x&&x.hi!=yl&&x.hi>y.hi);}void dfs(int y,int k,int p,int s){    ds[p]=s;    fo(i,k+1,n)     {        if(z[i].lw<y&&z[i].hi>y)         {            bool pd=0;            if(!b1[i]) b1[i]=++n1,n1++,pd=1;            if(abs(z[i].hi-y)>abs(y-z[i].lw))            {                link(p,b1[i],abs(z[i].hi-y));                link(p,b1[i]+1,abs(y-z[i].lw));            }            else            {                link(p,b1[i]+1,abs(y-z[i].lw));                link(p,b1[i],abs(z[i].hi-y));            }            if(pd)            {                dfs(z[i].hi,i,b1[i],s+abs(z[i].hi-y));                dfs(z[i].lw,i,b1[i]+1,s+abs(y-z[i].lw));            }            break;        }        if(z[i].lw==yl&&z[i].x==xl)         {            if(!ed) ed=++n1;            link(p,ed,abs(z[i].hi-y));            break;        }    }}int main(){    cin>>xl>>yl;    cin>>n;    st=1;    z[1].x=z[1].hi=z[1].lw=0;    n++;    fo(i,2,n)    {        int x,y,p,q;        scanf("%d %d %d %d",&x,&y,&p,&q);        if(y>q) swap(y,q);        if(x>p) swap(x,p);        x--,q++,y--;        z[i].x=x,z[i].hi=q,z[i].lw=y;    }    z[++n].x=xl,z[n].hi=z[n].lw=yl;    sort(z+1,z+n+1,cmp);    st=1,ed=0;    int i=1;    n1=1;    while(z[i].x<0&&z[i].lw!=0) i++;    memset(ds,107,sizeof(ds));    dfs(0,i,1,0);    spfa();    printf("%d\n",dis[ed]+xl);}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手指画颜料变干怎么办 刮画纸画错了怎么办 电脑绘的图不能扩大怎么办 华腾同步课堂忘记密码怎么办 被缝纫机针扎了怎么办 大小孩抢了孩子玩具怎么办 无锡天一初中考不进天一高中怎么办 校考一个都没过怎么办 拼音会拼不会写怎么办 20岁出头很迷茫怎么办 出了社会很迷茫怎么办 2018年现在会计工作难找怎么办 开广告店没生意怎么办 淘宝没有7天退怎么办 吃了松香的鸭子怎么办 理科生考电影专业研究生怎么办 pr导出视频很慢怎么办 8岁儿童头发稀少怎么办 八岁儿童版头发怎么办 小孩子有一块不长头发怎么办 小孩子头发上长癣怎么办 一岁多头发少怎么办 孩子头发长得慢怎么办 小孩头发长得慢怎么办 头发出油不洗头怎么办 青少年掉头发很厉害怎么办 洗了冷水头头痛怎么办 头发烫染后干枯毛躁怎么办 扎不起来的短发怎么办 发际线掉头发怎么办偏方 头上脓包掉头发怎么办 小孩头发少又黄怎么办 发旋哪里头发少怎么办 每次洗头发都掉好多怎么办 10岁儿童掉头发怎么办 1岁半宝宝掉头发怎么办 头发掉发严重怎么办吃什么 掉了一块钱很气怎么办 头发软又少怎么办盘头 头发出油掉的厉害怎么办 头发很油又少怎么办