「十二省聯考 2019」字符串問題
解題思路
傻逼題..
考慮問題轉化為一個A串向其支配的所有B串的后綴A串連邊,如果有環答案 \(-1\) 否則是這個 \(\text{DAG}\) 上最長路徑,直接建圖是 \(n^2\) 的,考慮優化建圖即可。
由於 \(A,B\) 都是原串的一個子串,那么對原串的反串建 SAM,一個子串的后綴就是其所在節點上比它長的串以及,其子樹里的所有串。
首先將所有 \(A,B\) 串在 SAM上用倍增定位並新建節點,把SAM上每個節點拆成入點和出點,對於SAM每一個節點上的 \(A,B\) 串節點按照長度排序和入點出點連成一條鏈,每個點再向其孩子連邊。此時直接讓 \(A\) 串對應點和 \(B\) 串對應點連邊即可。由於要保證 \(A\) 串必須要經過其支配的 \(B\) 串才能到另外一個 \(A\) 串,所以不要把 \(A\) 串的貢獻直接記在鏈上的節點,再新建一個節點記在這個節點上面然后讓原來的節點連一條邊到它即可,總復雜度 \(\mathcal O(nlogn)\)。
具體建邊看代碼吧,直接講可能不太能講清楚,反正這個題挺無腦的,下午拿到題40分鍾就寫完過了。
code
/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 2000005;
int na, nb;
namespace graph{
queue<int> q;
vector<int> g[N];
int deg[N], n; ll val[N], dis[N];
inline void addedge(int x, int y){
g[x].push_back(y), deg[y]++, n = max(n, max(x, y));
}
inline void solve(){
for(int i = 1; i <= n; i++) if(!deg[i]) q.push(i);
int tot = 0;
for(; !q.empty(); q.pop()){
int u = q.front();
dis[u] += val[u], tot++;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
dis[v] = max(dis[v], dis[u]);
if(!--deg[v]) q.push(v);
}
}
if(tot != n) return (void) (puts("-1"));
ll ans = 0;
for(int i = 1; i <= n; i++) ans = max(ans, dis[i]);
printf("%lld\n", ans);
}
inline void clear(){
for(int i = 1; i <= n; i++)
deg[i] = dis[i] = val[i] = 0, g[i].clear();
n = 0;
}
}
inline bool cmp(pair<int, int> A, pair<int, int> B){
return A.first != B.first ? A.first < B.first : A.second > B.second;
}
namespace SAM{
vector<pair<int, int> > s[N];
vector<int> g[N];
int len[N], pos[N], nid[N], f[N][22], fa[N], ch[N][26], size = 1, tail = 1, total;
inline int newnode(int x){ return len[++size] = x, size; }
inline void ins(int c, int id){
int p = tail, np = newnode(len[p] + 1); pos[id] = np;
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) return (void) (fa[np] = 1, tail = np);
int q = ch[p][c];
if(len[q] == len[p] + 1) fa[np] = q;
else{
int nq = newnode(len[p] + 1);
fa[nq] = fa[q], fa[q] = fa[np] = nq;
for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}tail = np;
}
inline void dfs(int u){
f[u][0] = fa[u];
for(int i = 1; i <= 20; i++) f[u][i] = f[f[u][i-1]][i-1];
for(int i = 0; i < (int) g[u].size(); i++)
graph::addedge(u + size, g[u][i]), dfs(g[u][i]);
}
inline void addedge1(){
for(int i = 2; i <= size; i++) g[fa[i]].push_back(i);
dfs(1);
}
inline void pushnode(int l, int r, int id){
int x = pos[l];
for(int i = 20; ~i; i--)
if(len[f[x][i]] >= r - l + 1) x = f[x][i];
s[x].push_back(make_pair(r - l + 1, id));
}
inline void addedge2(){
for(int i = 1; i <= size; i++){
sort(s[i].begin(), s[i].end(), cmp);
for(int j = 0; j < (int) s[i].size(); j++){
int x = s[i][j].second;
nid[x] = x + size * 2, x += size * 2;
if(j == 0) graph::addedge(i, x);
if(j == (int) s[i].size() - 1) graph::addedge(x, i + size);
else graph::addedge(x, s[i][j+1].second + size * 2);
if(x <= size * 2 + na){
++total;
int u = size * 2 + na + nb + total;
graph::addedge(x, u);
graph::val[u] = s[i][j].first, nid[x-2*size] = u;
}
}
if(!(int) s[i].size()) graph::addedge(i, i + size);
}
}
inline void clear(){
for(int i = 1; i <= size; i++){
memset(ch[i], 0, sizeof(ch[i]));
fa[i] = len[i] = 0, g[i].clear(), s[i].clear();
}
size = tail = 1, total = 0;
}
}
char str[N];
inline void realmain(){
scanf("%s", str + 1); int n = strlen(str + 1);
for(int i = n; i; i--) SAM::ins(str[i] - 'a', i);
SAM::addedge1();
read(na);
for(int i = 1, l, r; i <= na; i++)
read(l), read(r), SAM::pushnode(l, r, i);
read(nb);
for(int i = 1, l, r; i <= nb; i++)
read(l), read(r), SAM::pushnode(l, r, na + i);
SAM::addedge2();
int m; read(m);
for(int i = 1, x, y; i <= m; i++){
read(x), read(y);
graph::addedge(SAM::nid[x], SAM::nid[y+na]);
}
graph::solve();
for(int i = 1; i <= na + nb; i++) SAM::nid[i] = 0;
for(int i = 1; i <= n; i++) SAM::pos[i] = 0;
SAM::clear(), graph::clear();
}
int main(){
int T; read(T); while(T--) realmain();
return 0;
}