Problem

平面上有一排n个点 ,为A1,A2··· An。
然后m个询问,每个询问两个数a,l表示a处挂一条长度为l的绳子。
这条绳子一直不停的绕,问最后绕着哪个点转。(刚落在一个点上,则就是这个点) 

Solution

用一个dfs不停的搜。然后对于剩余长度,二分找到下一个绕上的点。
可以优化:绳子可能会绕着两点不停地转,此时可以直接模两点距离的两倍。

Notice

1.输入的A数组时无序的,需要排序。
2.两点之间的距离的两倍,会爆int。所以要开longlong
3.记录编号的数组,我没开longlong就爆了。至今原因不明。

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define reg register int
#define rep(i, a, b) for (reg i = a; i <= b; i++)
#define per(i, a, b) for (reg i = a; i >= b; i--)
#define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
const int INF = 1e9, N = 2000000;
const double eps = 1e-6, phi = acos(-1.0);
ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
ll val[N + 5];
ll id[N + 5], t[N + 5];
ll n;

ll dfs(ll now, ll len, ll left, ll right)
{
	if (len == 0 || left == right) return now;
	len %= (val[right] - val[left]) * 2;
	ll pos = upper_bound(val + 1, val + n + 1, val[now] + len) - val - 1;
	if (pos > now) return dfs(pos, len - abs(val[pos] - val[now]), left, pos);
	pos = lower_bound(val + 1, val + n + 1, val[now] - len) - val;
	if (pos < now) return dfs(pos, len - abs(val[pos] - val[now]), pos, right);
	return now;
}

int cmp(ll X, ll Y)
{
	return val[X] < val[Y];
}

int sqz()
{
	n = read();
	ll m = read();
	rep(i, 1, n) val[i] = read(), id[i] = i;
	sort(id + 1, id + n + 1, cmp);
	sort(val + 1, val + n + 1);
	rep(i, 1, n) t[id[i]] = i;
	
	while(m--)
	{
		ll x = t[read()];
		ll y = read();
		write(id[dfs(x, y, 1, n)]), puts("");
	}
	return 0;
}
posted on 2017-09-27 20:16  WizardCowboy  阅读(224)  评论(0)    收藏  举报