【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;
}
posted @ 2020-10-14 19:38  stoorz  阅读(111)  评论(0编辑  收藏  举报