2022牛客多校4 E Jobs (Hard Version)

题目描述

https://ac.nowcoder.com/acm/contest/33189/E

简要题意:给定 $n$ 三元组 $(x_i,y_i,z_i)$,每个三元组有一个颜色 $c_i$,现在有 $q$ 次询问,每次询问给定一个三元组 $(x_i,y_i,z_i)$,求有多少种颜色的三元组 $(x_j,y_j,z_j)$ 满足 $x_j\le x_i,y_j\le y_i,z_j\le z_i$,强制在线

$n,q\le 2\times 10^6,1\le x_i,y_i,z_i\le 400$

Solution

注意到三元组的权值范围很小,我们考虑对于每个位置预处理答案

从二维入手,对于同一种颜色的二元组,我们按照 $x_i$ 排序,容易发现 $x_i\le x_j,y_i\le y_j$ 的 $(x_j,y_j)$ 是没有用的,我们直接将其删除即可,那么剩下的二元组一定满足第一位递减,第二维递增,那么我们可以做一个这样的容斥

vZPEPx.png

考虑三维如何处理,我们按照第三维排序,然后用 $set$ 维护前两维的情况动态加入和删除即可

时间复杂度 $O(n\log n +400^3+q)$

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <algorithm>
#include <set>
#include <random>
#define maxn 1000010
#define maxm 410
#define ll long long
using namespace std;

const int p = 998244353;

int n, q;

int d[maxm][maxm][maxm];

struct node {
int x, y, z;

friend bool operator < (const node &u, const node &v) {
if (u.x == v.x) return u.y < v.y;
return u.x < v.x;
}
} a[maxn]; set<node> S;

inline void del(set<node>::iterator it, int z) {
--d[it -> x][it -> y][z];
auto pre = it, nxt = next(it);
if (nxt != S.end()) ++d[nxt -> x][it -> y][z];
if (it != S.begin()) pre = prev(it), ++d[it -> x][pre -> y][z];
if (pre != it && nxt != S.end()) --d[nxt -> x][pre -> y][z];
S.erase(it);
}

inline void add(node x) {
++d[x.x][x.y][x.z];
auto it = S.insert(x).first, pre = it, nxt = next(it);
if (nxt != S.end()) --d[nxt -> x][it -> y][it -> z];
if (it != S.begin()) pre = prev(it), --d[it -> x][pre -> y][it -> z];
if (pre != it && nxt != S.end()) ++d[nxt -> x][pre -> y][it -> z];
}

bool check_n(node x) {
auto it = S.upper_bound(x);
if (it == S.end()) return 0;
if (it -> y >= x.y) return del(it, x.z), 1;
else return 0;
}

bool check_p(node x) {
auto it = S.upper_bound(x);
if (it == S.begin()) return 0;
if (prev(it) -> y <= x.y) return 1;
else return 0;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n >> q;
for (int o = 1; o <= n; ++o) {
int l; vector<node> vec; cin >> l;
for (int i = 1; i <= l; ++i) cin >> a[i].x >> a[i].y >> a[i].z;
sort(a + 1, a + l + 1, [](const node &u, const node &v) { return u.z < v.z; });
S.clear();
for (int i = 1; i <= l; ++i) {
while (check_n(a[i])) ;
if (!check_p(a[i])) add(a[i]);
}
} const int N = 400;
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j)
for (int k = 1; k <= N; ++k) d[i][j][k] += d[i - 1][j][k];
for (int j = 1; j <= N; ++j)
for (int i = 1; i <= N; ++i)
for (int k = 1; k <= N; ++k) d[i][j][k] += d[i][j - 1][k];
for (int k = 1; k <= N; ++k)
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j) d[i][j][k] += d[i][j][k - 1];
int seed; cin >> seed;
mt19937 rng(seed);
uniform_int_distribution<> u(1, 400);
ll ans = 0, lans = 0;
while (q--) {
int IQ = (u(rng) ^ lans) % 400 + 1;
int EQ = (u(rng) ^ lans) % 400 + 1;
int AQ = (u(rng) ^ lans) % 400 + 1;
lans = d[IQ][EQ][AQ];
ans= (ans * seed + lans) % p;
} cout << ans << "\n";
return 0;
}