[CF] D. Robot Queries - Educational Codeforces Round 159 (Rated for Div. 2)

https://codeforces.com/contest/1902/problem/D

题目大意

给出某 LRUD 组成的 $n \ (\le 2 \times 10^5)$ 的操作序列 $S$ 以及 $q \ (\le 2 \times 10^5)$ 个询问。询问之间彼此独立。每次问,将原始操作序列 $[l, r]$ 的这一段反转后,整个操作序列以 $(0, 0)$ 为起点会不会通过 $(x, y)$。($S$ 翻转 $[l, r]$ 之后的序列为 $s_0 s_1 s_2 \cdots s_{l - 1} s_r s_{r - 1} s_{r - 2} \cdots s_{l + 1} s_l s_{r + 1} s_{r + 2} \cdots s_n$。)

简要题解

观察:

执行一串操作之后,只与每种操作次数有关,与顺序无关。我们假定 $pos[i]$ 表示执行了 $i$ 次操作之后的位置,则,$[l, r]$ 翻转不会影响,$0 \sim i-1$ 和 $r \sim n$ 的 $pos$ 的值。于是我们可以用前后缀分别处理每个询问,在翻转区间外是否已经经过了点。

对于翻转的区间,我们注意到,这里翻转后的路径和翻转前有一定的对称关系。假设要求的点为 $p$,其位于翻转后的序列在$l - 1$ 次操作之后又执行了 $k$ 次操作的位置,假定这 $k$ 次操作造成的相对于 $pos[l - 1]$ 的偏移向量为 $v = p - pos[l - 1]$ 则显然,在原序列里,这一段操作发生在结尾,即由 $p' = pos[r - k]$ 偏移 $v$ 之后到达 $pos[r]$。可以列出等式 $v = p - pos[l - 1] = pos[r] - p'$。

当然这里我们不知道 $k$ 的值,我们只需要找 $r$ 之前,最后出现的 $p'$ 对应的 pos 中的下标,如果这个下标是晚于 $l$ 的,则说明找到了。

复杂度

$T$:$O(n \log n)$

$S$:$O(n)$

代码实现

#include <bits/stdc++.h>
using namespace std;

int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();

using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;

template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) { 
    return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) { 
    return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z 
    if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
    if(x<z) { y=x; x=z; } else if(y<z) y=z; }

// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());

/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/

typedef array<int, 4> A4;

map<char, int> dx, dy;
void init() {
  dx['U'] = 0;
  dx['D'] = 0;
  dx['L'] = -1;
  dx['R'] = 1;
  dy['U'] = 1;
  dy['D'] = -1;
  dy['L'] = 0;
  dy['R'] = 0;
}

void solve() {
  int n, q; cin >> n >> q;
  string op; cin >> op;
  int x, y, l, r;
  vector<vector<A4>> qs(n + 1), qs2(n + 1);
  for (int i = 0; i < q; i++) {
    cin >> x >> y >> l >> r;
    qs[l].push_back({x, y, r, i});
    qs2[r].push_back({x, y, l, i});
  }

  vector<int> px, py;
  px.push_back(0);
  py.push_back(0);
  for (int i = 0; i < n; i++) {
    px.push_back(px.back() + dx[op[i]]);
    py.push_back(py.back() + dy[op[i]]);
  }

  // for (int i : px) cerr << i << ' '; 
  // cerr << endl;
  // for (int i : py) cerr << i << ' '; 
  // cerr << endl;

  vector<int> ans(q);

  set<PII> se;
  for (int i = 0; i <= n; i++) {
    for (auto&& [x, y, r, id] : qs[i]) {
      if (se.count({x, y})) {
        ans[id] = 1;
      }
    }
    se.insert({px[i], py[i]});
  }

  se.clear();
  for (int i = n; i >= 0; i--) {
    se.insert({px[i], py[i]});
    for (auto&& [x, y, l, id] : qs2[i]) {
      if (se.count({x, y})) {
        ans[id] = 1;
      }
    }
  }

  // 0 1 2 3 4 5
  //   [     ]    [1, 4] -> 1 3

  map<PII, int> lst;
  for (int i = 0; i <= n; i++) {
    for (auto&& [x, y, l, id] : qs2[i]) {
      int nx = px[i] + px[l - 1] - x, ny = py[i] + py[l - 1] - y;

      // cerr << x << ' ' << y << ' ' << l << ' ' << i << ' ';
      // cerr << px[l - 1] << ' ' << px[r] << ' ' << py[l - 1] << ' ' << py[i] << ' ';
      // cerr << nx << ' ' << ny << endl;

      if (auto it = lst.find({nx, ny}); it != lst.end()) {
        if (it->second >= l) {
          ans[id] = 1;
        }
      }
    }

    lst[{px[i], py[i]}] = i;
  }

  for (int i : ans) {
    cout << (i ? "YES" : "NO") << '\n';
  }
}

int main() {
  init();
  int t = 1; 
  // cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}
Prev: [CF] E. Collapsing Strings - Educational Codeforces Round 159 (Rated for Div. 2)
Next: [CF] C. Insert and Equalize - Educational Codeforces Round 159 (Rated for Div. 2)