XXI Open Cup Grand Prix of Korea J.Remote Control

无穷大的二位网格平面上, $(0, 0)$ 处有一个障碍物. 现在有一个由 R, L, U, D 组成的长度为 $n$ 的操作序列和一个机器人. 操作序列表示控制机器人如何走(上下左右), 如果机器人的下一步是障碍物(即原点), 那么他不行动. 现在有 $Q$ 次询问, 每次询问给出机器人的起点, 问终点. 保证机器人不在 $(0, 0)$.

$1 \le n, q \le 3 \cdot 10^5$

jyz nb!

不要被"一个“给误导了, 把所有询问都放在图上, 然后同时开始执行操作, 想象一下, 是不是有种"背景在动"的感觉? 没错, 这就是 “相对运动”. 与其操作 $Q$ 个机器人, 不如反向操作一个障碍物. 假设在障碍物移动的过程中, 没有碰到任何机器人, 那么障碍物移动的轨迹反一下, 就是所有机器人移动的轨迹了. 障碍物移动的轨迹可以通过二位向量前缀和求得. 统计答案每个机器人起点对它做差即可. 于是, 对于障碍物移动过程中碰到的机器人, 我们想办法改变机器人的起点, 使得其终点不变, 但不再碰见障碍物. 这是好办的, 因为障碍物碰见机器人了的话, 就证明机器人在这个时候会去撞障碍物(相对运动), 那么让机器人"后退"一步, 再执行这个操作, 后续操作是一模一样的. 所以做法就是, 相对运动移动障碍物, 碰到机器人就"推"一下. 需要注意的是, 障碍物移动一下最多推 $n$ 个机器人, 但是这些机器人在后续操作中就等价了, 所以只用搞一个代表出来就行, 用并查集合并一下即可.

复杂度 $O(\alpha n)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
int fa[MAXN];

void init(int n) {
  for (int i = 1; i <= n; i++) fa[i] = i;
}

int find(int x) {
  return x == fa[x] ? x : fa[x] = find(fa[x]);
}

bool uni(int x, int y) {
  if (find(x) == find(y))
    return false;
  fa[find(x)] = find(y);
  return true;
}

struct Vec {
  int x, y;
  Vec operator + (const Vec &B) const { return Vec{x + B.x, y + B.y}; }
  Vec operator - (const Vec &B) const { return Vec{x - B.x, y - B.y}; }
  bool operator == (const Vec &B) const {
    return x == B.x && y == B.y;
  }
  bool operator < (const Vec &V) const {
    return x == V.x ? y < V.y : x < V.x;
  }
} d[256], ans[MAXN];

map<Vec, int> mp;
int n, q;
char str[MAXN];

int main() {
  d['U'] = {0, 1};
  d['D'] = {0, -1};
  d['L'] = {-1, 0};
  d['R'] = {1, 0};
  scanf("%d%s%d", &n, str, &q);
  init(q);
  for (int i = 1; i <= q; i++) {
    Vec cur;
    scanf("%d%d", &cur.x, &cur.y);
    if (mp[cur])
      uni(i, mp[cur]);
    else
      mp[cur] = i;
  }
  Vec cur = {0, 0};
  for (int i = 0; str[i]; i++) {
    cur = cur - d[str[i]];
    if (mp[cur]) {
      Vec nxt = cur - d[str[i]];
      if (mp[nxt])
        uni(mp[cur], mp[nxt]);
      else
        mp[nxt] = mp[cur];
      mp.erase(cur);
    }
  }
  for (auto [v, i] : mp)
    ans[i] = v - cur;
  for (int i = 1; i <= q; i++)
    printf("%d %d\n", ans[find(i)].x, ans[find(i)].y);
  return 0;
}