[直线关系][思维]Mr. Main and Windmills 第45届icpc区域赛昆明站I

Mr. Main took a train from city sss to city ttt and passed a plain full of windmills. The train ran in a straight line. A windmill is a machine used for wind power generation. Its fan blades rotate when the wind blows. From his perspective, colorful windmills lined up on the horizon from left to right.
 
As the train was running, the order of windmills from his perspective was constantly changing: a windmill was originally on the left/right of another, and then changed to its right/left; 

Given the coordinates of the windmills, please find the coordinate of him when he just observed the hhh-th windmill exchanged order with other windmills for the kkk-th times. It is guaranteed that any three of the points given, the cities and the windmills, were not collinear, and that all of the windmills were on the same side of the line that the train ran along.
 



As shown in the picture, in Mr. Mian's perspective, B was initially to the left of A, and later to the right of A.

输入描述:

The first line of input contains two integers nnn and mmm, where n(1≤n≤1000)n(1\leq n\leq 1000)n(1≤n≤1000) is number of windmills, and m(1≤m≤104)m(1\leq m\leq 10^4)m(1≤m≤104) is number of queries.

The second line contains four integers xsx_sxs​, ysy_sys​, xtx_txt​ and yty_tyt​ (−106≤xs,ys,xt,yt≤106-10^6\leq x_s,y_s,x_t,y_t\leq 10^6−106≤xs​,ys​,xt​,yt​≤106), which are the coordinates of the starting city s and destination city t.

The next nnn lines describe the windmills, the iii-th of which contains two integers xix_ixi​, 
yiy_iyi​ (−106≤xi,yi≤106-10^6\leq x_i,y_i\leq 10^6−106≤xi​,yi​≤106), which are the coordinates of the iii-th windmill.

The next mmm lines describe the queries, the iii-th of which contains two integers, hih_ihi​ and kik_iki​ (1≤hi≤n,1≤ki≤1061\leq h_i\leq n,1\leq k_i\leq 10^61≤hi​≤n,1≤ki​≤106), denoting a query for the coordinates when observing the kik_iki​-th pass of the hih_ihi​-th windmill.

输出描述:

Output m lines, each containing two real numbers xi,yix_i, y_ixi​,yi​, representing the coordinates when the hih_ihi​-th windmill is observed to exchange order with other windmills for k times; if it does not exist, output -1. Your answer is considered correct if its absolute or relative error with the standard answer is less than 10−510^{-5}10−5.

示例1

输入

4 2
0 0 5 0
1 3
2 4
4 1
4 5
1 2
3 2

输出

-1
4.6666666667 0.0000000000

题意: 有一条线路从s点到t点,道路的一侧存在一些电线杆,当车辆从s点驶向t点时,电线杆在车上人的视线里会发生顺序变换,如题目中图片所示。现在给出n个电线杆的坐标,以及m次询问,每次询问给出要观测的电线杆编号h以及参数k,求h号电线杆在全部电线杆中顺序发生第k次变化时车上人的坐标。

分析: 模拟样例可以发现,对于每次询问某个确定的点p,其在视野中顺序变化的位置只出现在与其他各点连线在路线上交点位置,因此问题转化为询问其他各点到p点的直线中有几条能与线段s~t相交,并且把交点记录下来。如下图所示,a点和b点即为点3在视野中顺序变换点。

考虑数据范围n < 1e3,m < 1e4,如果对于每次询问都暴力处理可能会超时,时间复杂度为O(n*m*logn),因此可以把每个点与其他各点连线在道路上的交点提前预处理出来,每次询问O(1)返回答案即可,总复杂度O(n*n*logn)。

处理每个点的时候把线段与直线各交点加入vector数组,之后对各数组排序,然后询问的时候直接输出就行。

具体代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include <cmath>
#include <vector>
using namespace std;
const double eps = 1e-8;
const int maxp = 1010;
int n, m;

int sgn(double x)
{
	if(fabs(x) < eps)
		return 0;
	if(x < 0)
		return -1;
	else
		return 1;
}
inline double sqr(double x){return x*x;}
struct Point
{
	double x, y;
	Point(double _x, double _y){x = _x, y = _y;}
	Point(){}
	void input(){scanf("%lf%lf", &x, &y);}
	bool operator == (Point b)const{return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;}
	bool operator < (Point b)const{return sgn(x-b.x) == 0 ? sgn(y-b.y)<0:x<b.x;}
	Point operator - (const Point &b)const{return Point(x-b.x, y-b.y);}
	double operator ^ (const Point &b)const{return x*b.y-y*b.x;}
	double operator * (const Point &b)const{return x*b.x+y*b.y;}
};
struct Line
{
	Point s, e;
	Line(Point _s, Point _e){s = _s, e= _e;}
	Point crosspoint(Line v)
	{
		double a1 = (v.e-v.s)^(s-v.s);
		double a2 = (v.e-v.s)^(e-v.s);
		return Point((s.x*a2-e.x*a1)/(a2-a1), (s.y*a2-e.y*a1)/(a2-a1));
	}
	int linecrosseg(Line v)
	{
		int d1 = sgn((e-s)^(v.s-s));
		int d2 = sgn((e-s)^(v.e-s));
		if((d1^d2) == -2)	return 2;
		return (d1 == 0 || d2 == 0);
	}
};

Point s, e;

bool cmp(Point x, Point y)
{
	return (x.x-s.x)*(x.x-s.x)+(x.y-s.y)*(x.y-s.y)<(y.x-s.x)*(y.x-s.x)+(y.y-s.y)*(y.y-s.y); 
}

Point p[maxp];
vector<Point> a[maxp];

signed main()
{
	cin >> n >> m;
	s.input(), e.input();
	Line l(s, e);
	for(int i = 1; i <= n; i++)
		p[i].input();
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			if(i == j)
				continue;
			Line temp(p[i], p[j]);
			if(temp.linecrosseg(l) == 0)
				continue;
			Point cross = temp.crosspoint(l);
			a[i].push_back(cross);
		}
	}
	for(int i = 1; i <= n; i++)
		sort(a[i].begin(), a[i].end(), cmp);
	for(int i = 1; i <= m; i++)
	{
		int h, k;
		scanf("%d%d", &h, &k);
		if(a[h].size() < k)
			puts("-1");
		else
			printf("%.10f %.10f\n",a[h][k-1].x, a[h][k-1].y);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值