F. Cutting Game

F. Cutting Game

Alice and Bob were playing a game again. They have a grid of size $a \times b$ ($1 \le a, b \le 10^9$), on which there are $n$ chips, with at most one chip in each cell. The cell at the intersection of the $x$-th row and the $y$-th column has coordinates $(x, y)$.

Alice made the first move, and the players took turns. On each move, a player could cut several (but not all) rows or columns from the beginning or end of the remaining grid and earn a point for each chip that was on the cut part of the grid. Each move can be described by the character 'U', 'D', 'L', or 'R' and an integer $k$:

  • If the character is 'U', then the first $k$ remaining rows will be cut;
  • If the character is 'D', then the last $k$ remaining rows will be cut;
  • If the character is 'L', then the first $k$ remaining columns will be cut;
  • If the character is 'R', then the last $k$ remaining columns will be cut.

Based on the initial state of the grid and the players' moves, determine the number of points earned by Alice and Bob, respectively.

Input

The first line contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases.

The first line of each test case contains four integers $a$, $b$, $n$, and $m$ ($2 \le a, b \le 10^9$, $1 \le n, m \le 2 \cdot 10^5$) — the dimensions of the grid, the number of chips, and the number of moves.

Each of the next $n$ lines contain two integers $x_i$ and $y_i$ ($1 \le x_i \le a$, $1 \le y_i \le b$) — the coordinates of the chips. All pairs of coordinates are distinct.

Each of the next $m$ lines contain a character $c_j$ and an integer $k_j$ — the description of the $j$-th move. It is guaranteed that $k$ is less than the number of rows/columns in the current grid. In other words, a player cannot cut the entire remaining grid on their move.

It is guaranteed that the sum of the values of $n$ across all test cases in the test does not exceed $2 \cdot 10^5$. It is guaranteed that the sum of the values of $m$ across all test cases in the test does not exceed $2 \cdot 10^5$.

Output

For each test case, output two integers — the number of points earned by Alice and Bob, respectively.

Example

input

6
4 4 3 2
4 1
3 3
2 4
D 2
R 1
4 4 3 3
4 1
3 2
2 3
D 1
L 1
U 2
3 5 3 2
1 3
2 2
3 3
R 2
R 2
6 4 4 2
1 4
2 3
5 3
1 1
R 1
U 1
9 3 2 1
6 1
3 3
D 8
10 10 2 5
7 5
9 1
R 1
L 2
D 1
U 4
D 1

output

2 1
2 0
0 3
1 1
2 0
0 1

Note

Below is the game from the first example:

On her turn, Alice cut $2$ rows from the bottom and scored $2$ points, then Bob cut $1$ column from the right and scored one point. Note that if Bob had cut $1$ row from the bottom, he would have also scored $1$ point.

 

解题思路

  实时维护矩形四个边界的值,用 $u$ 表示上边界,$d$ 表示下边界,$l$ 表示左边界,$r$ 表示右边界,初始时有 $u = 1, \, d = a, \, l = 1, \, r = b$。

  • 对于操作 U,本质是想知道左上角为 $(u, l)$ 右下角为 $(u+k-1, r)$ 的矩形内点的数量。
  • 对于操作 D,本质是想知道左上角为 $(d-k+1, l)$ 右下角为 $(d, r)$ 的矩形内点的数量。
  • 对于操作 L,本质是想知道左上角为 $(u, l)$ 右下角为 $(d, l+k-1)$ 的矩形内点的数量。
  • 对于操作 R,本质是想知道左上角为 $(u, r-k+1)$ 右下角为 $(d, r)$ 的矩形内点的数量。

  因此每次的操作相当于询问某个矩形内点的个数,这就可以用二维数点去做。对于左上角为 $(x_1,y_1)$ 右下角为 $(x_2,y_2)$ 的矩形的询问,运用前缀和与容斥的思想,拆分成四个左上角均为 $(1,1)$ ,右下角分别为 $(x_2, y_2)$,$(x_2, y_1-1)$,$(x_1-1, y_2)$,$(x_1-1, y_1-1)$ 的矩形,并分别求出形如该矩阵内点的个数,依次记作 $s_1, \, s_2, \, s_3, \, s_4$,那么原本询问的点的数量就是 $s_1 - s_2 - s_3 + s_4$。

  把所有询问都拆成这 $4$ 种矩形,并按照右下角的 $x$ 从小到大排序。最后在枚举这些矩形的过程中依次把点的纵坐标加到树状数组中进行维护,求某个左上角为 $(1,1)$ 右下角为 $(x,y)$ 的矩形内点的个数,只需在树状数组中求纵坐标不超过 $y$ 的点的数量。为此需要对可能出现的纵坐标的值进行离散化。

  AC 代码如下,时间复杂度为 $O(n \log{n} + m \log{(n+m)})$:

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

typedef long long LL;

const int N = 2e5 + 5, M = N * 2;

array<int, 2> p[N];
struct Query {
    char c;
    int k;
}q[N];
int xs[M], sz;
array<int, 4> g[N * 4];
int tr[M];

int lowbit(int x) {
    return x & -x;
}

void add(int x) {
    for (int i = x; i <= sz; i += lowbit(i)) {
        tr[i]++;
    }
}

int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret += tr[i];
    }
    return ret;
}

int find(int x) {
    int l = 1, r = sz;
    while (l < r) {
        int mid = l + r >> 1;
        if (xs[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return l;
}

void solve() {
    int a, b, n, m;
    cin >> a >> b >> n >> m;
    sz = 0;
    for (int i = 0; i < n; i++) {
        cin >> p[i][0] >> p[i][1];
        xs[++sz] = p[i][1];
    }
    xs[++sz] = 0, xs[++sz] = b;
    for (int i = 0, l = 1, r = b; i < m; i++) {
        cin >> q[i].c >> q[i].k;
        if (q[i].c == 'L') l += q[i].k, xs[++sz] = l - 1;
        else if (q[i].c == 'R') r -= q[i].k, xs[++sz] = r;
    }
    sort(xs + 1, xs + sz + 1);
    sz = unique(xs + 1, xs + sz + 1) - xs - 1;
    for (int i = 0, j = 0, u = 1, d = a, l = 1, r = b; i < m; i++) {
        int x1 = u, y1 = l, x2 = d, y2 = r;
        if (q[i].c == 'U') u += q[i].k, x2 = u - 1;
        else if (q[i].c == 'D') d -= q[i].k, x1 = d + 1;
        else if (q[i].c == 'L') l += q[i].k, y2 = l - 1;
        else r -= q[i].k, y1 = r + 1;
        g[j++] = {x2, y2, 1, i};
        g[j++] = {x2, y1 - 1, -1, i};
        g[j++] = {x1 - 1, y2, -1, i};
        g[j++] = {x1 - 1, y1 - 1, 1, i};
    }
    sort(g, g + 4 * m);
    sort(p, p + n);
    array<int, 2> ans({0});
    memset(tr, 0, sz + 1 << 2);
    for (int i = 0, j = 0; i < m << 2; i++) {
        while (j < n && p[j][0] <= g[i][0]) {
            add(find(p[j++][1]));
        }
        ans[g[i][3] & 1] += g[i][2] * query(find(g[i][1]));
    }
    cout << ans[0] << ' ' << ans[1] << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round #946 (Div. 3) Editorial:https://codeforces.com/blog/entry/129686

posted @ 2024-05-21 15:28  onlyblues  阅读(67)  评论(0编辑  收藏  举报
Web Analytics