Description
Solution
显然是建图跑最长路一类的问题,我们需要将类串连向,仅当是的前缀时成立。而所有的类串和类串均选自同一大串,故若将的后缀树建出来,这种前缀关系就很好在后缀树上表示出来了。
后缀树上对于点,它可以做它所有子节点的前缀。
而构造目标串的过程是:先选择一个类串,然后可以通过这个所支配的类串的后面接上一个,满足的前缀是,重复上述过程直到无可匹配。
那么随便怎么建一下图就可以了。
至于构造的目标串能否无限长,只需要看建出的图有没有环即可。
务必用拓扑排序实现。Spfa只有暴力分
code_by_uselessName
#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define GET getchar()
#define LL long long
using namespace std;
namespace FastIO{
inline int read(){
int s=0,f=1;char t=GET;
while('0'>t||t>'9'){if(t=='-')f=-1;t=GET;}
while('0'<=t&&t<='9'){s=(s<<1)+(s<<3)+t-'0';t=GET;}
return s*f;
}
}
using FastIO::read;
const int N=200005;
const int M=2000005;
const int An=400005;
const int Am=26;
const int lim=19;
int n,na,nb,tot,Bac[An];
LL dp[M];
int Ina[N],Outa[N],Inb[N],Outb[N];
int prt[An][20];
struct Node{
int len,fla,id;
};
bool cmp(Node a,Node b){
if(a.len!=b.len)return a.len<b.len;
return a.fla>b.fla;
}
vector<Node>Inf[An];
namespace SuffixAuto{
int root,lst,cnt,len[An],ch[An][Am],fle[N],fa[An],sum[N],sa[An];
int Make(int _len){
len[++cnt]=_len;
return cnt;
}
void Init(){
root=lst=Make(0);
}
void Insert(int v,int _pos){
int p=lst,_id=Make(len[p]+1);fle[_pos]=lst=_id;
while(p&&(!ch[p][v]))ch[p][v]=_id,p=fa[p];
if(!p)fa[_id]=root;
else{
int Nxt=ch[p][v];
if(len[p]+1==len[Nxt])fa[_id]=Nxt;
else{
int rep=Make(len[p]+1);
for(int i=0;i<26;i++)ch[rep][i]=ch[Nxt][i];
fa[rep]=fa[Nxt];fa[Nxt]=fa[_id]=rep;
while(p&&ch[p][v]==Nxt)ch[p][v]=rep,p=fa[p];
}
}
}
void Topsort(){
memset(sum,0,sizeof(sum));
for(int i=1;i<=cnt;i++)sum[len[i]]++;
for(int i=1;i<=n;i++)sum[i]+=sum[i-1];
for(int i=1;i<=cnt;i++)sa[sum[len[i]]--]=i;
}
}
using namespace SuffixAuto;
struct line{
int Nxt,to,val;
}l[M];
int h[M],lcnt,In[M];
void Link(int u,int v,int w){
l[++lcnt]=(line){h[u],v,w};h[u]=lcnt;In[v]++;
}
int Topsum;
void __Topsort(){
queue<int>q;
for(int i=1;i<=tot;i++)if(!In[i])q.push(i);
while(q.size()){
int u=q.front();q.pop();Topsum++;
for(int i=h[u],v;i;i=l[i].Nxt){
v=l[i].to;
dp[v]=max(dp[v],dp[u]+l[i].val);
if(!(--In[v]))q.push(v);
}
}
}
void buildGraph(){
tot=cnt;Topsort();
for(int i=1;i<=na;i++)Ina[i]=++tot,Outa[i]=++tot;
for(int i=1,u;i<=cnt;i++){
u=sa[i];Bac[u]=u;
if(fa[u])Link(Bac[fa[u]],u,0);
if(Inf[u].size()){
sort(Inf[u].begin(),Inf[u].end(),cmp);
for(int j=0,id;j<Inf[u].size();j++){
id=Inf[u][j].id;
if(Inf[u][j].fla==1){
Link(Bac[u],Ina[id],0);
Link(Ina[id],Outa[id],Inf[u][j].len);
}
else Link(Bac[u],Inb[id]=Outb[id]=++tot,0),Bac[u]=tot;
}
}
}
int m=read();
for(int i=1,a,b;i<=m;i++){
a=read();b=read();
Link(Outa[a],Inb[b],0);
}
}
void LCAInit(){
for(int i=1;i<=cnt;i++)prt[i][0]=fa[i];
for(int j=1;j<=lim;j++)
for(int i=1;i<=cnt;i++)prt[i][j]=prt[prt[i][j-1]][j-1];
}
void Climb(int pos,Node _Inf){
pos=fle[pos];
for(int k=lim;k>=0;k--)if(prt[pos][k]&&len[prt[pos][k]]>=_Inf.len)pos=prt[pos][k];
Inf[pos].push_back(_Inf);
}
char s[N];
void Clear(){
for(int u=1;u<=cnt;u++){
fa[u]=len[u]=prt[u][0]=0;
Inf[u].clear();
memset(ch[u],0,sizeof(ch[u]));
}
for(int u=1;u<=tot;u++)h[u]=In[u]=dp[u]=0;
root=cnt=lcnt=tot=Topsum=0;
}
void Solve(){
scanf("%s",s+1);n=strlen(s+1);Init();
for(int i=n;i>=1;i--)Insert(s[i]-'a',i);LCAInit();
na=read();
for(int i=1,l,r;i<=na;i++){
l=read();r=read();
if(l<1||l>r||r>n)l=1,r=0;
Climb(l,(Node){r-l+1,1,i});
}
nb=read();
for(int i=1,l,r;i<=nb;i++){
l=read();r=read();
if(l<1||l>r||r>n)l=1,r=0;
Climb(l,(Node){r-l+1,2,i});
}
buildGraph();
__Topsort();
if(Topsum!=tot)cout<<"-1\n";
else{
LL Max=0;
for(int i=1;i<=na;i++)Max=max(Max,dp[Outa[i]]);
cout<<Max<<'\n';
}
Clear();
}
int main(){
int Case=read();
while(Case--)Solve();
return 0;
}