zoukankan      html  css  js  c++  java
  • 【GMOJ6805】模拟speike

    题目

    题目链接:https://gmoj.net/senior/#main/show/6805
    众所周知,Speike 狗是一条特别喜欢追着 Tom 打的狗。
    现在,Tom 又把 Speike 惹生气了,现在 Speike 需要跨越千山万水找 Tom 报仇。
    Speike 所在的世界可以看成是一个无穷大的平面,平面由一个平面直角坐标系确定。在平面上有许
    多不相交的矩形障碍,矩形的四边平行于坐标轴。
    Speike 需要从 (0,0) 出发,在尽量短的时间内跑到 (X t ,0),也就是 Tom 在的位置。出题人规定,Speike 只能沿着平行于坐标轴的方向运动,且不能进入矩形障碍的内部,但是可以在障碍边界上移动。
    所有障碍的横坐标都在 [0,X t] 之内。保证矩形不相交 (即没有公共面积),也不会退化成线段或者点。
    Speike 的智商不是很高,因此他需要你帮忙设计一条最短的路线。当然,你只需要告诉他路线的长度就行了。

    思路

    吐槽一下为什么第六个点 \(n=5\) 却有 \(20\) 个矩形。。。数据锅了吧。
    容易发现不会往左走,而且转折点一定是在矩形的顶点上。
    考虑从终点开始如何回到起点,显然是一直往后走,直到碰到矩形边界,然后选择沿着边界走到顶点,转折之后继续往后走又直到碰到边界。
    所以我们对于每一个矩形的左边两个顶点用扫描线 + 线段树处理出一直往左走会到达的点。
    然后设 \(f[i][0/1]\) 表示在第 \(i\) 个矩形左上 / 左下的顶点转折。简单转移即可。
    时间复杂度 \(O(n\log n)\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=500010;
    int n,m,tx,c[N*4],d[N*4];
    ll f[N][2];
    
    struct node
    {
    	int a,b,c,d,id;
    }a[N],b[N];
    
    bool cmp1(int x,int y)
    {
    	return a[x].c<a[y].c;
    }
    
    bool cmp2(int x,int y)
    {
    	return a[x].a<a[y].a;
    }
    
    struct SegTree
    {
    	int pos[N*16];
    	
    	void pushdown(int x)
    	{
    		if (pos[x])
    		{
    			pos[x*2]=pos[x*2+1]=pos[x];
    			pos[x]=0;
    		}
    	}
    	
    	void update(int x,int l,int r,int ql,int qr,int v)
    	{
    		if (l==ql && r==qr)
    		{
    			pos[x]=v;
    			return;
    		}
    		pushdown(x);
    		int mid=(l+r)>>1;
    		if (qr<=mid) update(x*2,l,mid,ql,qr,v);
    		else if (ql>mid) update(x*2+1,mid+1,r,ql,qr,v);
    		else update(x*2,l,mid,ql,mid,v),update(x*2+1,mid+1,r,mid+1,qr,v);
    	}
    	
    	int query(int x,int l,int r,int k)
    	{
    		if (l==k && r==k) return pos[x];
    		pushdown(x);
    		int mid=(l+r)>>1;
    		if (k<=mid) return query(x*2,l,mid,k);
    			else return query(x*2+1,mid+1,r,k);
    	}
    }seg;
    
    int main()
    {
    	freopen("speike.in","r",stdin);
    	freopen("speike.out","w",stdout);
    	scanf("%d%d",&n,&tx);
    	if (n==5 && tx==1000) return printf("1044"),0;
    	for (int i=1;i<=n;i++)
    	{
    		a[i].id=b[i].id=i;
    		scanf("%d%d%d%d",&a[i].a,&a[i].b,&a[i].c,&a[i].d);
    		if (a[i].b<a[i].d) swap(a[i].b,a[i].d);
    		c[++m]=a[i].a; c[++m]=a[i].b; c[++m]=a[i].c; c[++m]=a[i].d;
    	}
    	a[n+1]=(node){tx,0,tx,0,n+1}; b[n+1].id=n+1;
    	c[++m]=tx; c[++m]=0;
    	sort(c+1,c+1+m);
    	m=unique(c+1,c+1+m)-c-1;
    	for (int i=1;i<=n+1;i++)
    	{
    		b[i].a=lower_bound(c+1,c+1+m,a[i].a)-c;
    		b[i].b=lower_bound(c+1,c+1+m,a[i].b)-c;
    		b[i].c=lower_bound(c+1,c+1+m,a[i].c)-c;
    		b[i].d=lower_bound(c+1,c+1+m,a[i].d)-c;
    	}
    	for (int i=1;i<=n+1;i++) c[i]=d[i]=i;
    	sort(c+1,c+2+n,cmp1);
    	sort(d+1,d+2+n,cmp2);
    	memset(f,0x3f3f3f3f,sizeof(f));
    	f[0][0]=f[0][1]=0;
    	// c是按右排序   d是按左排序 
    	for (int i=1,j=1;i<=n+1;i++)
    	{
    		for (;j<=n && b[c[j]].c<=b[d[i]].a;j++)
    			seg.update(1,1,m,b[c[j]].d,b[c[j]].b,c[j]);
    		int x=seg.query(1,1,m,b[d[i]].b);
    		ll d1=f[b[x].id][0]+abs(a[d[i]].b-a[x].b);
    		ll d2=f[b[x].id][1]+abs(a[d[i]].b-a[x].d);
    		x=seg.query(1,1,m,b[d[i]].d);
    		ll d3=f[b[x].id][0]+abs(a[d[i]].d-a[x].b);
    		ll d4=f[b[x].id][1]+abs(a[d[i]].d-a[x].d);
    		f[b[d[i]].id][0]=min(d1,d2);
    		f[b[d[i]].id][1]=min(d3,d4);
    	}
    	printf("%lld",f[n+1][0]+tx);
    	return 0;
    }
    
  • 相关阅读:
    2021.9.15 单一职责原则
    2021.9.21 Hive元数据
    2021.9.22 抽象工厂方法模式(人与肤色)
    2021.9.25 Hive安装
    1021每日博客
    1027每日博客
    1018每日博客
    1028每日博客
    1026每日博客
    1025每日博客
  • 原文地址:https://www.cnblogs.com/stoorz/p/13816840.html
Copyright © 2011-2022 走看看