Description
给出一个字符串(S)和若干个(A)类串和(B)类串,保证两类串都是(S)的子串,并且在给出若干组支配关系((x,y))表示一个编号为(x)的(A)类串支配编号为(y)的(B)类串,现在你需要求出一个长度最长的(T)串满足(T)可以被划分为若干个(A)类串,并且第(i)个(A)类串存在一个支配的(B)类串是第(i+1)个(A)类串的前缀
Solution
考虑我们如果将一个(B)类串向所有该串是其前缀的(A)类串连边,然后在将支配关系连边,那么我们得到的必定是一个(DAG),否则无解,所以只需要对其进行一遍拓扑排序(DP)就好了
考虑怎么进行连边,这里首先考虑对反串建出一个(SAM),那么一个(B)类串就只需要向他在(parent)树上的子树中所有(A)类串连边就好了,但是由于会存在某些(A)类串和(B)类串在同一个点上,所以我们需要将这些点按照串长将他从(parent)树中拆出来就好了,最后子树连边直接做一遍(DFS)序然后线段树优化建图即可,复杂度(O(nlog n+mlog n))
事实上还有一种优秀的建图方式,就是考虑每个(A)类串直接由离他最近的一个祖先(B)类串连边就好了,这样就可以将点数和边数都做到(O(n))
Code
//Created Time:2020年05月04日 星期一 20时50分42秒
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1000006
#define pi pair<int, int>
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
using namespace std;
void chmax(long long &x, long long y){x = x >= y ? x : y;}
int n, na, nb, m, tot, num;
int pos[N], ida[N], idb[N], lena[N], lenb[N], sz[N], dfn[N], book[N], id[N], deg[N];
char s[N];
long long dis[N];
vector<pi> nd[N], e[N];
vector<int> son[N];
int read();
void work();
bool cmp(pi ,pi);
void build(int ,int ,int);
void link(int ,int ,int ,int ,int, int);
//{{{SAM
struct SAM{
int cnt, lst;
int fa[N], len[N], ch[N][26], d[N], rk[N], fath[N][20];
void clear(){
for(int i = 1; i <= cnt; ++i){
id[i] = dfn[i] = sz[i] = book[i] = d[i] = fa[i] = len[i] = 0;
memset(ch[i], 0, sizeof ch[i]);
memset(fath[i], 0, sizeof fath[i]);
vector<pi>().swap(nd[i]);
vector<int>().swap(son[i]);
}
cnt = lst = 1; tot = 0;
return ;
}
int ins(int x){
int np = ++cnt, p = lst; lst = np; len[np] = len[p] + 1;
for(; p && !ch[p][x]; p = fa[p]) ch[p][x] = np;
if(!p) fa[np] = 1;
else{
int q = ch[p][x];
if(len[q] == len[p] + 1) fa[np] = q;
else{
int nq = ++cnt; memcpy(ch[nq], ch[q], sizeof ch[nq]);
fa[nq] = fa[q]; fa[q] = fa[np] = nq; len[nq] = len[p] + 1;
for(; p && ch[p][x] == q; p = fa[p]) ch[p][x] = nq;
}
}
return np;
}
void get(){
for(int i = 1; i <= cnt; ++i) ++d[len[i]];
for(int i = 1; i <= cnt; ++i) d[i] += d[i - 1];
for(int i = cnt; i >= 1; --i) rk[d[len[i]]--] = i;
for(int i = 1; i <= cnt; ++i){
int u = rk[i]; fath[u][0] = fa[u];
for(int j = 1; j <= 19; ++j)
fath[u][j] = fath[fath[u][j - 1]][j - 1];
}
return ;
}
void find(int u, int x, int flag){
for(int i = 19; ~i; --i)
if(len[fath[u][i]] >= (flag ? lena[x] : lenb[x]))
u = fath[u][i];
nd[u].pb(mkp(x, flag));
return ;
}
void dfs(int u){
dfn[u] = tot;
if(book[u] >= 2) dfn[u] = ++tot, sz[u] = 1, lena[tot] = len[u];
for(auto v : son[u])
dfs(v), sz[u] += sz[v];
return ;
}
void rebuild(){
for(int i = 1; i <= cnt; ++i){
if(nd[i].empty()) continue;
sort(nd[i].begin(), nd[i].end(), cmp);
int lst = fa[i];
for(auto p : nd[i]){
int u = p.fi, op = p.se;
if(len[lst] == (op ? lena[u] : lenb[u]) && book[lst] != op + 1) book[lst] = 3;
else if(len[lst] != (op ? lena[u] : lenb[u])){
fa[++cnt] = lst; len[cnt] = op ? lena[u] : lenb[u];
book[cnt] = op + 1; lst = cnt;
}
(op ? ida[u] : idb[u]) = lst;
continue;
}
fa[i] = lst;
}
for(int i = 1; i <= cnt; ++i) son[fa[i]].push_back(i);
dfs(1); return ;
}
}sam;
//}}}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
int T; cin >> T;
while(T--)
work();
return 0;
}
int read(){
int x = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar());
for(; isdigit(ch); ch = getchar()) x = x * 10 + (ch - '0');
return x;
}
bool cmp(pi x, pi y){
int lenx = x.se ? lena[x.fi] : lenb[x.fi];
int leny = y.se ? lena[y.fi] : lenb[y.fi];
return lenx < leny;
}
void work(){
scanf("%s", s + 1); n = strlen(s + 1);
sam.clear(); long long ans = 0;
for(int i = n; i; --i) pos[i] = sam.ins(s[i] - 'a');
na = read(); sam.get();
for(int i = 1; i <= na; ++i){
int l = read(), r = read();
lena[i] = r - l + 1;
chmax(ans, lena[i] * 1ll);
sam.find(pos[l], i, 1);
}
nb = read();
for(int i = 1; i <= nb; ++i){
int l = read(), r = read();
lenb[i] = r - l + 1;
sam.find(pos[l], i, 0);
}
num = 0; sam.rebuild();
build(1, 1, tot);
int lim = num;
for(int i = 1; i <= nb; ++i){
int u = idb[i]; idb[i] = ++num;
if(book[u] != 3)
link(1, 1, tot, dfn[u] + 1, dfn[u] + sz[u], num);
else link(1, 1, tot, dfn[u], dfn[u] + sz[u] - 1, num);
}
m = read();
for(int i = 1; i <= m; ++i){
int x = read(), y = read();
e[id[dfn[ida[x]]]].pb(mkp(idb[y], 0));
++deg[idb[y]];
}
queue<int> Q;
for(int i = 1; i <= num; ++i){
dis[i] = 0;
if(!deg[i]){
if(i > lim) dis[i] = -999999999;
Q.push(i);
}
}
int cnt = 0;
while(!Q.empty()){
int u = Q.front(); Q.pop(); ++cnt;
chmax(ans, dis[u]);
for(auto p : e[u]){
int v = p.fi, w = p.se;
chmax(dis[v], dis[u] + w);
--deg[v];
if(!deg[v]) Q.push(v);
}
}
if(cnt != num) puts("-1");
else printf("%lld
", ans);
for(int i = 1; i <= num; ++i)
vector<pi>().swap(e[i]), deg[i] = 0;
return ;
}
#define ls pos << 1
#define rs pos << 1 | 1
void build(int pos, int l, int r){
num = max(num, pos);
if(l == r) return id[l] = pos, void();
int mid = (l + r) >> 1;
build(ls, l, mid); build(rs, mid + 1, r);
if(l == mid) e[pos].pb(mkp(ls, lena[l]));
else e[pos].pb(mkp(ls, 0));
if(mid + 1 == r) e[pos].pb(mkp(rs, lena[r]));
else e[pos].pb(mkp(rs, 0));
++deg[ls]; ++deg[rs];
return ;
}
void link(int pos, int l, int r, int nl, int nr, int p){
if(nl > nr) return ;
if(l >= nl && r <= nr){
++deg[pos];
if(l == r)
e[p].pb(mkp(pos, lena[l]));
else e[p].pb(mkp(pos, 0));
return ;
}
int mid = (l + r) >> 1;
if(mid >= nl) link(ls, l, mid, nl, nr, p);
if(mid < nr) link(rs, mid + 1, r, nl, nr, p);
return ;
}
#undef ls
#undef rs