H-Hopping Rabbit_2021牛客暑期多校训练营6

H-Hopping Rabbit

题目

链接:
https://ac.nowcoder.com/acm/contest/11257/H
来源:牛客网
题目大意:
一只兔子在草原上跳来跳去,草原上有猎人布下的n个陷阱.现在将草原看作一个二维直角坐标系,兔子看作一个点,陷阱看作一个矩阵(且它的边必定与x轴或y轴平行),兔子每次会沿x轴或y轴方向移动距离d(即如果兔子在(x,y),它跳一次后在(x+d,y),
(x-d,y),(x,y+d),(x,y-d)四个点中的一个.问在坐标系中是否存在一个点(x0+0.5,y0+0.5),使兔子无论怎么跳都不会掉进陷阱.如果存在,第一行输出"YES",第二行输出任意一个满足条件的x0和y0,中间用k空格隔开.否则输出"NO".

思路

首先,我们可以想象得出来,如果一组数据有解,那么一定有解在由(0,0),(0,d-1),
(d-1,d-1),(d-1,0)这4个点依次连接所形成的矩形里(因为我们可以将矩形平移,每次平移d个单位,平移后矩形内部的点是不符合题意的).所以我们先将所有矩形移至第一象限,这样便于计算,但是有的矩形会很大,平移后超出了这个范围(如下图).在这里插入图片描述
这时我们就要将矩形再次平移,将它向下,向左,同时向下和向左d个单位,并把平移后在红色范围内的部分留下.然后用扫描线+线段树来对矩形进行下一步的操作.具体见代码.

代码实现

#include<iostream>
#include<algorithm> 
#include<vector>
using namespace std;
const int N=100010;
int n,d,l1,r1,xx;
bool flag=0;
struct tree{
	int len,cnt;
}a[N*4];

struct xian{
	int tl,tr;//左右边坐标 
	int x; 
};
vector<xian> x[N];

void pushup(int l,int r,int rt){ 
	if(a[rt].cnt)
		a[rt].len=r-l+1;
	else if(l==r)
		a[rt].len=0;
	else 
		a[rt].len=a[rt*2].len+a[rt*2+1].len;
}

void add(int x1,int y1,int x2,int y2){//将扫描线加入动态数组中 
	x[x1].push_back((xian){y1,y2,1});
	x[x2+1].push_back((xian){y1,y2,-1});
}

void md(int &x){
	x%=d;
	if(x<0) x+=d;
}

void change(int l,int r,int rt){//离散化 
	if(l1<=l&&r<=r1){
		a[rt].cnt+=xx;
		pushup(l,r,rt);
		return;
	}
	int mid=(l+r)/2;
	if(l1<=mid) change(l,mid,2*rt);
	if(mid<r1) change(mid+1,r,2*rt+1);
	pushup(l,r,rt);
}

void get(int l,int r,int rt){
	if(a[rt].len==0){
		printf("%d\n",l);
		return;
	}
	int mid=(l+r)/2;
	if(a[2*rt].len<mid-l+1) get(l,mid,2*rt);
	else get(mid+1,r,2*rt+1);
}

int main(){
	scanf("%d%d",&n,&d);
	int m=0;
	for(int i=1;i<=n;i++){
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		x2--; 
		y2--;
		if(x2-x1+1>=d)
			x1=0,x2=d-1;
		if(y2-y1+1>=d)
			y1=0,y2=d-1;
		md(x1),md(x2),md(y1),md(y2);
		if(x1<=x2)
		{
			if(y1<=y2) add(x1,y1,x2,y2);
			else add(x1,0,x2,y2),add(x1,y1,x2,d-1);
		}
		else
		{
			if(y1<=y2) add(0,y1,x2,y2),add(x1,y1,d-1,y2);
			else add(0,0,x2,y2),add(x1,y1,d-1,d-1),add(0,y1,x2,d-1),add(x1,0,d-1,y2);
		}
	}
	for(int i=0;i<d;i++)
	{
		for(int j=0;j<x[i].size();j++){
			l1=x[i][j].tl;
			r1=x[i][j].tr;
			xx=x[i][j].x;
			change(0,d-1,1);
		}
		if(a[1].len<d)
		{
			printf("YES\n%d ",i);
			get(0,d-1,1);
			return 0;
		}
	}
	printf("NO\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值