Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P4849 寻找宝藏

P4849 寻找宝藏

四维偏序,排序 + CDQ + CDQ + 树状数组 。一个问题:在这类用左侧信息更新右侧信息的问题中,必须将左侧完全计算完才能用于更新右侧,因此 CDQ 的顺序一定是中序遍历,这样就不能归并排序,用 $O(n \log n)$ 排序就会使复杂度增高,因此最后一层使用树状数组而非继续 CDQ ,复杂度可以保证为 $O(n \log ^ 3 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
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <cstdio>
#include <vector>
#include <algorithm>
#define fi first
#define se second
#define eb emplace_back
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
if (c == '-') flag = true;
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 3) + (x << 1) + c - '0';
if (flag) x = ~x + 1;
}
template <class Type, class ...Rest>
void read (Type &x, Rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
if (x < 0) putchar('-'), x = ~x + 1;
if (x > 9) write(x / 10);
putchar('0' + x % 10);
}
typedef long long L;
typedef pair <L, int> PLI;
const int N = 8e4 + 10, mod = 998244353;
void adj (int &x) { x += x >> 31 & mod; }
int n, m;
PLI f[N], tr[N];
PLI operator + (PLI x, int k) { return { x.fi + k, x.se }; }
struct Node { bool op; int a, b, c, d, v, id; } w[N];
bool cmp4 (Node &x, Node &y)
{ return x.d < y.d || (x.d == y.d && x.op > y.op); }
bool cmp3 (Node &x, Node &y)
{ return x.c < y.c || (x.c == y.c && cmp4(x, y)); }
bool cmp2 (Node &x, Node &y)
{ return x.b < y.b || (x.b == y.b && cmp3(x, y)); }
bool cmp1 (Node &x, Node &y)
{ return x.a < y.a || (x.a == y.a && cmp2(x, y)); }
void chkmax (PLI &x, PLI k)
{
if (k.fi > x.fi) x = k;
else if (k.fi == x.fi) adj(x.se += k.se - mod);
}
void add (int x, PLI k)
{
for (; x <= m; x += x & -x)
chkmax(tr[x], k);
}
PLI query (int x)
{
PLI res { 0, 0 };
for (; x; x -= x & -x)
chkmax(res, tr[x]);
return res;
}
void clear (int x)
{
for (; x <= m; x += x & -x)
tr[x] = { 0, 0 };
}
void cdq2 (int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
cdq2(l, mid);
vector <Node> tmp (w + l, w + r + 1);
sort(w + l, w + mid + 1, cmp3), sort(w + mid + 1, w + r + 1, cmp3);
for (int i = l, j = mid + 1; i <= mid || j <= r; )
{
for (; i <= mid && (j > r || !cmp3(w[j], w[i])); ++i)
if (w[i].op) add(w[i].d, f[w[i].id]);
for (; j <= r && (i > mid || cmp3(w[j], w[i])); ++j)
if (!w[j].op) chkmax(f[w[j].id], query(w[j].d) + w[j].v);
}
for (int i = l; i <= mid; ++i)
if (w[i].op) clear(w[i].d);
for (int i = l; i <= r; ++i) w[i] = tmp[i - l];
cdq2(mid + 1, r);
}
void cdq1 (int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
cdq1(l, mid);
vector <Node> tmp (w + l, w + r + 1);
for (int i = l; i <= mid; ++i) w[i].op = true;
sort(w + l, w + r + 1, cmp2);
cdq2(l, r);
for (int i = l; i <= r; ++i) w[i] = tmp[i - l];
cdq1(mid + 1, r);
}
int main ()
{
read(n, m);
vector <int> ws;
for (int i = 1; i <= n; ++i)
{
read(w[i].a, w[i].b, w[i].c, w[i].d, w[i].v);
ws.eb(w[i].d);
}
sort(ws.begin(), ws.end());
m = ws.erase(unique(ws.begin(), ws.end()), ws.end()) - ws.begin();
for (int i = 1; i <= n; ++i)
w[i].d = upper_bound(ws.begin(), ws.end(), w[i].d) - ws.begin();
sort(w + 1, w + n + 1, cmp1);
for (int i = 1; i <= n; ++i) f[w[i].id = i] = { w[i].v, 1 };
cdq1(1, n);
PLI res = { 0, 0 };
for (int i = 1; i <= n; ++i) chkmax(res, f[i]);
write(res.fi), puts(""), write(res.se);
return 0;
}