Jzoj5234 外星人的路径

227 篇文章 3 订阅
153 篇文章 0 订阅
有一个外星人控制了你的大脑。一开始你处于原点(0,0)。外星人有一个由(R,U,D,L)组成的长度为M 的操作序列,分别代表(右,上,下,左)。

平面上有N 个关键点,每当外星人给出一个操作,你需要在这个方向上找到最近的一个关键点,并走到那个点上。保证输入数据合法。

100%的数据,N,M≤100000,xi,yi≤200000。

这样,我们搞2个权值线段树,一个存横坐标一个存纵坐标,每次查询当前坐标的前继或者后续即可

复杂度O(mlgn)

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define M 200010
#define ls s[x].l
#define rs s[x].r
using namespace std;
struct nod{ int l,r,s; };
struct Tree{
	nod s[3000000];
	int rt[M<<1],c;
	Tree(){ 
		c=0; s[0]=(nod){0,0,0};
		memset(rt,0,sizeof rt);
	}
	inline int newnode(){ return ++c; }
	void ps(int x){ s[x].s=s[ls].s+s[rs].s; }
	void insert(int l,int r,int& x,int p){
		if(!x) x=newnode();
		if(l==r){ s[x].s=1; return; }
		int m=l+r>>1;
		if(p<=m) insert(l,m,ls,p);
		  else insert(m+1,r,rs,p);
		ps(x);
	}
	int getmax(int l,int r,int x){
		for(int m;l<r;){
			m=l+r>>1;
			if(s[rs].s) { l=m+1; x=rs; }
			else { r=m; x=ls; }
		}
		return l;
	}
	int getmin(int l,int r,int x){
		for(int m;l<r;){
			m=l+r>>1;
			if(s[ls].s) { r=m; x=ls; }
			else { l=m+1; x=rs; }
		}
		return l;
	}
	int getpre(int l,int r,int x,int p){
		if(l==r) return p;
		int m=l+r>>1,v;
		if(p<=m) return getpre(l,m,ls,p);
		else v=getpre(m+1,r,rs,p);
		if(v!=p||!s[ls].s) return v;
		else return getmax(l,m,ls);
	}
	int getsuc(int l,int r,int x,int p){
		if(l==r) return p;
		int m=l+r>>1,v;
		if(p>m) return getsuc(m+1,r,rs,p);
		else v=getsuc(l,m,ls,p);
		if(v!=p||!s[rs].s) return v;
		else return getmin(m+1,r,rs);
	}
	void insert(int x,int y){ insert(1,M<<1,rt[x],y); }
	int pre(int x,int y){ return getpre(1,M<<1,rt[x],y); }
	int suc(int x,int y){ return getsuc(1,M<<1,rt[x],y); }
} rot,lin;
int n,m,x,y; char s[100010];
int main(){
	freopen("tratincice.in","r",stdin);
	freopen("tratincice.out","w",stdout);
	scanf("%d%d",&n,&m);
	rot.insert(M,M);
	lin.insert(M,M);
	for(int i=0;i<n;++i){
		scanf("%d%d",&x,&y);
		x+=M; y+=M;
		rot.insert(x,y);
		lin.insert(y,x);
	}
	x=y=M; scanf("%s",s);
	for(int i=0;i<m;++i){
		if(s[i]=='U') y=rot.suc(x,y);
		if(s[i]=='D') y=rot.pre(x,y);
		if(s[i]=='L') x=lin.pre(y,x);
		if(s[i]=='R') x=lin.suc(y,x);
	}
	printf("%d %d\n",x-M,y-M);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值