0%

[十二省联考2019]字符串问题

题目描述

给定子串集合 \(A\)\(B\),和支配关系,构造最长目标串满足由 \(A\) 构成,对于相邻 \(A\),后一个存在前缀为 \(B\),且被 \(A\) 支配

题解

很明显,这道题的目的是优化建图,由于在练习 \(SAM\),所以就不考虑 \(SA\)

对于原串建一颗后缀树,发现题目中的建边正好是对于后缀树子树的连边,直接 \(DFS\) 序搞一下线段树优化建图跑个拓扑就行了

但注意,对于倍增向上跳的节点对于后 \(20\) 分不完全合法,只向部分连边,所以当时口胡的做法是每个节点按长度在排个序,再搞一次线段树优化建图就行了 但嫌麻烦直接打了个暴力交了,居然水过去了

一定要算好空间,两次死在空间上

最后注意 \(long\ long\) 神仙数据构造

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
#include <queue>
using namespace std;
typedef long long int64;
inline int read(int f = 1, int x = 0, char ch = ' ')
{
while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
return f*x;
}
const int N = 4e6+5;
int T;
int ns, na, nb, n, m;
int last = 1, tot = 1, ch[N][26], fa[N], len[N], pos[N];
char s[N];
int p[N], tax[N];
void insert(int c)
{
int cur = ++tot, pre = last; last = cur;
len[cur] = len[pre]+1; pos[ns-len[cur]+1] = cur;
while(pre&&!ch[pre][c]) ch[pre][c] = cur, pre = fa[pre];
if(!pre) return void(fa[cur] = 1);
int x = ch[pre][c];
if(len[pre]+1 == len[x]) return void(fa[cur] = x);
int y = ++tot; fa[y] = fa[x]; fa[x] = fa[cur] = y; len[y] = len[pre]+1;
memcpy(ch[y], ch[x], sizeof(ch[y]));
while(pre&&ch[pre][c] == x) ch[pre][c] = y, pre = fa[pre];
}
vector<pair<int, int> > sub[N];
vector<int> edge[N];
pair<int, int> b[N];
int seg[N], in[N], out[N], ac[20][N], w[N], deg[N], dfn[N], t;
void add(int x, int y) { edge[x].push_back(y); ++deg[y]; }
int find(int x, int d)
{
for(int i = 19; ~i; --i) if(len[ac[i][x]] >= d) x = ac[i][x];
return x;
}
void dfs(int x)
{
in[x] = ++t; dfn[t] = x;
for(int i = 0; i < edge[x].size(); ++i) dfs(edge[x][i]);
out[x] = t;
}
void build(int x, int l, int r)
{
seg[x] = ++n;
if(l == r)
{
for(int i = 0; i < sub[dfn[l]].size(); ++i)
add(seg[x], sub[dfn[l]][i].second);
}
else
{
int mid = (l+r)>>1;
build(x<<1, l, mid); build(x<<1|1, mid+1, r);
add(seg[x], seg[x<<1]); add(seg[x], seg[x<<1|1]);
}
}
void update(int x, int l, int r, int ql, int qr, int d)
{
if(ql <= l&&r <= qr) return add(d, seg[x]);
int mid = (l+r)>>1;
if(ql <= mid) update(x<<1, l, mid, ql, qr, d);
if(qr > mid) update(x<<1|1, mid+1, r, ql, qr, d);
}
queue<int> q;
int64 f[N];
int64 topo()
{
int64 ret = 0; int cnt = 0; memset(f, 0, sizeof(f));
for(int x = 1; x <= n; ++x) if(!deg[x]) q.push(x);
while(q.size())
{
int x = q.front(); q.pop();
f[x] += w[x]; ++cnt;
for(int i = 0; i < edge[x].size(); ++i)
{
int y = edge[x][i];
f[y] = max(f[x], f[y]);
if(--deg[y] == 0) q.push(y);
}
ret = max(f[x], ret);
}
return cnt == n?ret:-1;
}
int main()
{
T = read();
while(T--)
{
scanf("%s", s+1); ns = strlen(s+1);
for(int i = ns; i; --i) insert(s[i]-'a');
for(int i = 1; i <= tot; ++i) ++tax[len[i]];
for(int i = 1; i <= tot; ++i) tax[i] += tax[i-1];
for(int i = tot; i; --i) p[tax[len[i]]--] = i;
for(int i = 2; i <= tot; ++i)
{
int x = p[i]; ac[0][x] = fa[x]; edge[fa[x]].push_back(x);
for(int k = 1; k < 20; ++k) ac[k][x] = ac[k-1][ac[k-1][x]];
}
dfs(1);
for(int i = 1; i <= tot; ++i) edge[i].clear();

na = read(); n = na;
for(int i = 1; i <= n; ++i)
{
int l = read(), r = read(); w[i] = r-l+1;
sub[find(pos[l], r-l+1)].push_back(make_pair(r-l+1, i));
}
build(1, 1, tot);

nb = read();
for(int i = 1; i <= nb; ++i)
{
int l = read(), r = read();
b[i] = make_pair(find(pos[l], r-l+1), r-l+1);
}

m = read();
for(int i = 1; i <= m; ++i)
{
int u = read(), v = read(), x = b[v].first;
if(in[x] < out[x]) update(1, 1, tot, in[x]+1, out[x], u);
for(int k = 0; k < sub[x].size(); ++k)
if(b[v].second <= sub[x][k].first)
add(u, sub[x][k].second);
}
printf("%lld\n", topo());
for(int i = 1; i <= tot; ++i)
memset(ch[i], 0, sizeof(ch[i])),
sub[i].clear(),
fa[i] = len[i] = pos[i] = p[i] = tax[i] = 0;
tot = last = 1; t = 0;
for(int i = 1; i <= n; ++i) edge[i].clear(), w[i] = 0, deg[i] = 0;
}
return 0;
}