题目大意
题太长了,自己读吧 QAQ。
令 $n = \vert S \vert$,则:
- 对于 $40 \%$ 的数据,$n_a \times n_b \le 2 \times 10^5$。
- 对于 $80 \%$ 的数据,$\vert A_i \vert \ge \vert B_i \vert$。
- 对于 $100 \%$ 的数据,$n, n_a, n_b, m \le 2 \times 10^5$。
思路分析
算法一
直接借助 Hash 暴力建图,做拓扑排序后 DP 求最长链即可。
时间复杂度 $O(n + n_a \times n_b + m)$,期望得分 $40$ 分。
算法二
可以发现复杂度的瓶颈在于 “如果 $B_j$ 是 $A_i$ 的前缀,则从 $B_j$ 向 $A_i$ 连一条边” 这一部分。如果有 $\vert A_i \vert \ge \vert B_i \vert$,那么连边的条件等价于:
对于串后缀排序,则 $B_j$ 对应的 $A$ 就会形成一段区间。这段区间可以通过在 $\text{height}$ 数组上倍增来找到。找到区间以后,我们使用线段树优化建图即可。
我们将 $n, n_a, n_b, m$ 看作同阶,时间复杂度 $O(n \log n)$,期望得分 $80$ 分。
算法三
如果不保证 $\vert A_i \vert \ge \vert B_i \vert$,那么连边的条件就多了一个,也就是增加了一维的限制。我们使用主席树来代替线段树优化建边即可。
我们将 $n, n_a, n_b, m$ 看作同阶,时间复杂度 $O(n \log n)$,期望得分 $100$ 分。
代码实现
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | using namespace std; |
7 | |
8 |
|
9 | typedef long long ll; |
10 | |
11 | struct event { |
12 | int type, id, x, y; |
13 | event(int type = 0, int id = 0, int x = 0, int y = 0): type(type), id(id), x(x), y(y) {} |
14 | friend bool operator< (const event &a, const event &b) { |
15 | return a.x == b.x ? a.type < b.type : a.x > b.x; |
16 | } |
17 | }; |
18 | |
19 | const int maxn = 2e5, maxm = 2 * maxn, maxv = 5e6, logn = 17; |
20 | int T, len, sa[maxn + 3], rnk[maxn + 3], _cnt[maxn + 3], a[maxn + 3], b[maxn + 3], hei[logn + 3][maxn + 3]; |
21 | int n, m, k, lg, l1[maxn + 3], ln1[maxn + 3], l2[maxn + 3], ln2[maxn + 3], deg[maxv + 3], tot, cnt, rt, ch[maxv + 3][2]; |
22 | char s[maxn + 3]; |
23 | event e[maxm + 3]; |
24 | queue<int> Q; |
25 | vector<int> G[maxv + 3]; |
26 | ll dp[maxv + 3]; |
27 | |
28 | void radix_sort(int a[], int b[], int k[], int n) { |
29 | fill(_cnt + 1, _cnt + n + 1, 0); |
30 | for (int i = 1; i <= n; i++) _cnt[k[i]]++; |
31 | for (int i = 2; i <= n; i++) _cnt[i] += _cnt[i - 1]; |
32 | for (int i = n; i; i--) b[_cnt[k[a[i]]]--] = a[i]; |
33 | } |
34 | |
35 | void suffix_sort(int n) { |
36 | for (int i = 1; i <= n; i++) _cnt[s[i] - 'a' + 1] = 1; |
37 | for (int i = 2; i <= 26; i++) _cnt[i] += _cnt[i - 1]; |
38 | for (int i = 1; i <= n; i++) rnk[i] = _cnt[s[i] - 'a' + 1]; |
39 | if (_cnt[26] == n) { for (int i = 1; i <= n; i++) sa[rnk[i]] = i; return; } |
40 | for (int k = 1; k < n; k *= 2) { |
41 | for (int i = 1; i <= n; i++) { |
42 | a[i] = rnk[i], b[i] = (i + k <= n ? rnk[i + k] : 0) + 1; |
43 | } |
44 | for (int i = 1; i <= n; i++) sa[i] = i; |
45 | radix_sort(sa, rnk, b, n), radix_sort(rnk, sa, a, n); |
46 | rnk[sa[1]] = 1; |
47 | for (int i = 2; i <= n; i++) { |
48 | rnk[sa[i]] = rnk[sa[i - 1]] + (a[sa[i]] != a[sa[i - 1]] || b[sa[i]] != b[sa[i - 1]]); |
49 | } |
50 | if (rnk[sa[n]] == n) return; |
51 | } |
52 | } |
53 | |
54 | void get_height(int n) { |
55 | for (int i = 1, j, t = 0; i <= n; hei[0][rnk[i++] - 1] = t) { |
56 | for (t = max(0, t - 1), j = sa[rnk[i] - 1]; s[i + t] == s[j + t]; t++); |
57 | } |
58 | } |
59 | |
60 | void add_edge(int u, int v) { |
61 | G[u].push_back(v), deg[v]++; |
62 | } |
63 | |
64 | |
65 | int build(int l, int r) { |
66 | int x = ++tot; |
67 | if (l == r) return ch[x][0] = 0, ch[x][1] = 0, x; |
68 | return ch[x][0] = build(l, mid), ch[x][1] = build(mid + 1, r), x; |
69 | } |
70 | |
71 | int grow(int bs, int l, int r, int y, int z) { |
72 | int x = ++tot; |
73 | ch[x][0] = ch[bs][0], ch[x][1] = ch[bs][1], add_edge(x, bs); |
74 | if (l == r) return add_edge(x, y), x; |
75 | if (z <= mid) ch[x][0] = grow(ch[bs][0], l, mid, y, z), add_edge(x, ch[x][0]); |
76 | else ch[x][1] = grow(ch[bs][1], mid + 1, r, y, z), add_edge(x, ch[x][1]); |
77 | return x; |
78 | } |
79 | |
80 | void solve(int x, int l, int r, int lx, int rx, int y) { |
81 | if (!x) return; |
82 | if (l >= lx && r <= rx) return add_edge(y, x), void(); |
83 | if (lx <= mid) solve(ch[x][0], l, mid, lx, rx, y); |
84 | if (rx > mid) solve(ch[x][1], mid + 1, r, lx, rx, y); |
85 | } |
86 | |
87 | int main() { |
88 | scanf("%d", &T); |
89 | while (T--) { |
90 | scanf("%s", s + 1), len = strlen(s + 1); |
91 | suffix_sort(len), get_height(len); |
92 | lg = 0; |
93 | for (int k = 1; 1 << k <= len - 1; k++) { |
94 | lg = k; |
95 | for (int i = 1, j = (1 << (k - 1)) + 1; i <= len - (1 << k); i++, j++) { |
96 | hei[k][i] = min(hei[k - 1][i], hei[k - 1][j]); |
97 | } |
98 | } |
99 | cnt = 0; |
100 | scanf("%d", &n); |
101 | for (int i = 1; i <= n; i++) { |
102 | scanf("%d %d", &l1[i], &ln1[i]), ln1[i] = ln1[i] - l1[i] + 1; |
103 | e[++cnt] = event(1, i, ln1[i], l1[i]); |
104 | } |
105 | scanf("%d", &m); |
106 | for (int i = 1; i <= m; i++) { |
107 | scanf("%d %d", &l2[i], &ln2[i]), ln2[i] = ln2[i] - l2[i] + 1; |
108 | e[++cnt] = event(2, i, ln2[i], l2[i]); |
109 | } |
110 | sort(e + 1, e + cnt + 1); |
111 | scanf("%d", &k); |
112 | for (int i = 1, x, y; i <= k; i++) { |
113 | scanf("%d %d", &x, &y), add_edge(x, y + n); |
114 | } |
115 | tot = n + m, rt = 0; |
116 | rt = build(1, len); |
117 | for (int i = 1; i <= cnt; i++) { |
118 | if (e[i].type == 1) { |
119 | rt = grow(rt, 1, len, e[i].id, rnk[e[i].y]); |
120 | } else { |
121 | int l = rnk[e[i].y], r = l; |
122 | for (int k = lg; ~k; k--) { |
123 | if (l - (1 << k) > 0 && hei[k][l - (1 << k)] >= e[i].x) l -= 1 << k; |
124 | } |
125 | for (int k = lg; ~k; k--) { |
126 | if (r + (1 << k) <= len && hei[k][r] >= e[i].x) r += 1 << k; |
127 | } |
128 | solve(rt, 1, len, l, r, e[i].id + n); |
129 | } |
130 | } |
131 | for (int i = 1; i <= tot; i++) { |
132 | dp[i] = i <= n ? ln1[i] : 0; |
133 | if (!deg[i]) Q.push(i); |
134 | } |
135 | cnt = 0; |
136 | ll ans = 0; |
137 | while (!Q.empty()) { |
138 | int u = Q.front(); |
139 | cnt++, Q.pop(), ans = max(ans, dp[u]); |
140 | for (int i = 0, v; i < G[u].size(); i++) { |
141 | v = G[u][i]; |
142 | dp[v] = max(dp[v], dp[u] + (v <= n ? ln1[v] : 0)); |
143 | if (!--deg[v]) Q.push(v); |
144 | } |
145 | } |
146 | if (cnt != tot) puts("-1"); |
147 | else printf("%lld\n", ans); |
148 | for (int i = 1; i <= tot; i++) { |
149 | G[i].clear(), deg[i] = 0; |
150 | } |
151 | } |
152 | return 0; |
153 | } |