这道题真的搞了将近一天啊。自闭。
首先四十分暴力很好拿。一看就可以后缀数组先求个hgt,然后对于每个b都暴力的枚举一下a,是前缀的连边。然后按拓扑序求最长路,到最后入度仍有不为0的就是有环,输-1。
然后发现找b是哪个a的前缀时复杂度太高了,考虑优化一下。因为前80分都有a长度大于b,所以如果a所在的后缀和b所在的后缀的lcp大于等于b的长度了,那b一定可以向a连边。那要是把a按rnk排序,b一定向一段连续的a连边,所以二分找出区间后就可以线段树优化建图了。
最后20分肝不动了,参考了一下别人的题解,说是主席树,看上去似乎很有道理。因为我们是想保证b只向长度大于等于它的a连边,同时保证a是连续的区间可以优化建图,那我们只要给a和b一起按长度排序,依次添加a进可持久化线段树就可以了。想起来似乎很不错,但调了好久啊,没怎么写过这种结合。建图时父节点向子节点连边,新建的不是叶子节点的节点向对应旧点连边(如果b是一个长度更小的a的前缀,它一定也是一个长度更大的起始于相同位置的a的前缀),叶子节点向对应的a连边。其他没啥不一样了好像。
注意一下数组大小,还有多组数据要初始化。(一开始我算的数组大小好像不太对,似乎随意往大里开了点就过了。
然后呢我这个程序大约是常数太大了,loj能过,洛谷上得吸氧过。其实感觉有些地方还能优化,但是肝不动了。
放成私密就没人知道。
有一个oj上过了就是过了。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=200010,NN=4800010;
struct edge{int y,next;
}data[NN*4];
struct substr{int l,r,len,tp,id;
}s1[2*N];
struct node{int l,r;
}tree[NN];
queue<int> q;
int T,n,m,na,nb,nn,num,num1;
long long ans,dis[NN];
int tak[N],rnk[N],tp[N],sa[N],hgt[N],h[NN],in[NN],lg[N],l1[NN],st[N][19],root[N];
char str1[N];
inline int read(){int x=0,f=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return f?-x:x;
}
inline void sort1(){for(int i=1;i<=m;i++)tak[i]=0;for(int i=1;i<=n;i++)tak[rnk[i]]++;for(int i=2;i<=m;i++)tak[i]+=tak[i-1];for(int i=n;i>=1;i--)sa[tak[rnk[tp[i]]]--]=tp[i];
}
inline void add1(int x,int y){data[++num].y=y;data[num].next=h[x];h[x]=num;in[y]++;
}
inline int queryst(int x,int y){int len=y-x+1;return min(st[x][lg[len]],st[y-(1<<lg[len])+1][lg[len]]);
}
bool cmp(substr i,substr j){if(i.len!=j.len)return i.len>j.len;return i.tp<j.tp;
}
void build(int a,int b){num1++;if(a==b)return;int mid=(a+b)>>1,numm1=num1;tree[numm1].l=num1+1;add1(numm1+na+nb,num1+1+na+nb);build(a,mid);tree[numm1].r=num1+1;add1(numm1+na+nb,num1+1+na+nb);build(mid+1,b);
}
int newtree(int p,int pa,int pb,int x,int u){if(pa==pb){++num1;add1(num1+na+nb,u);add1(num1+na+nb,p+na+nb);return num1;}int mid=(pa+pb)>>1,ll,rr;if(x<=mid){ll=newtree(tree[p].l,pa,mid,x,u);rr=tree[p].r;}else{ll=tree[p].l;rr=newtree(tree[p].r,mid+1,pb,x,u);}tree[++num1].l=ll;tree[num1].r=rr;add1(num1+na+nb,ll+na+nb);add1(num1+na+nb,rr+na+nb);add1(num1+na+nb,p+na+nb);return num1;
}
void add(int p,int pa,int pb,int a,int b,int x){if(a<=pa&&pb<=b){add1(x,p+na+nb);return;}int mid=(pa+pb)>>1;if(a<=mid)add(tree[p].l,pa,mid,a,b,x);if(mid<b)add(tree[p].r,mid+1,pb,a,b,x);
}
int main(){freopen("string7.in","r",stdin);T=read();lg[1]=0;for(int p=1,cnt=0,i=2;i<=200000;i++){if(i==p<<1){lg[i]=++cnt;p<<=1;}else lg[i]=cnt;}while(T--){scanf("%s",str1+1);n=strlen(str1+1);for(int i=1;i<=n;i++){rnk[i]=str1[i]-'a'+1;tp[i]=i;}str1[n+1]='&';tp[n+1]=n+1;rnk[n+1]=27;n++;m=27;sort1();for(int p=0,w=1;p<n;w<<=1,m=p){p=0;for(int i=1;i<=w;i++)tp[++p]=n-w+i;for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;sort1();swap(tp,rnk);rnk[sa[1]]=p=1;for(int i=2;i<=n;i++){if(tp[sa[i]]!=tp[sa[i-1]]||tp[sa[i]+w]!=tp[sa[i-1]+w])p++;rnk[sa[i]]=p;}}for(int x,j=0,i=1;i<=n;i++){if(j)j--;x=sa[rnk[i]-1];while(str1[i+j]==str1[x+j])j++;hgt[rnk[i]]=j;}for(int i=0;i<n;i++)st[i][0]=hgt[i+1];for(int j=1;(1<<j)<=n;j++)for(int i=0;i+(1<<j)-1<n;i++)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);memset(l1,0,sizeof l1);na=read();for(int i=1;i<=na;i++){s1[i].l=read();s1[i].r=read();s1[i].tp=0;s1[i].len=s1[i].r-s1[i].l+1;s1[i].id=i;l1[i]=s1[i].len;}nb=read();for(int i=1;i<=nb;i++){s1[i+na].l=read();s1[i+na].r=read();s1[i+na].tp=1;s1[i+na].len=s1[i+na].r-s1[i+na].l+1;s1[i+na].id=i+na;}sort(s1+1,s1+na+nb+1,cmp);num=0;memset(h,-1,sizeof h);memset(in,0,sizeof in);num1=0;root[0]=1;build(1,n);for(int cnt=0,i=1;i<=na+nb;i++){if(!s1[i].tp){root[cnt+1]=newtree(root[cnt],1,n,rnk[s1[i].l],s1[i].id);cnt++;}else{int ll,rr,l,r,mid;ll=1;rr=rnk[s1[i].l]-1;while(ll<=rr){mid=(ll+rr)>>1;if(queryst(mid,rnk[s1[i].l]-1)>=s1[i].len)rr=mid-1;else ll=mid+1;}l=ll;ll=rnk[s1[i].l];rr=n-1;while(ll<=rr){mid=(ll+rr)>>1;if(queryst(rnk[s1[i].l],mid)>=s1[i].len)ll=mid+1;else rr=mid-1;}r=rr+1;add(root[cnt],1,n,l,r,s1[i].id);}}nn=read();for(int x,y,i=1;i<=nn;i++){x=read();y=read();add1(x,y+na);}memset(dis,-1,sizeof dis);while(!q.empty())q.pop();for(int i=1;i<=num1+nb+na;i++)if(!in[i]){dis[i]=1ll*l1[i];q.push(i);}while(!q.empty()){int u=q.front();q.pop();for(int i=h[u];i!=-1;i=data[i].next){int v=data[i].y;if(dis[v]<dis[u]+l1[v])dis[v]=dis[u]+l1[v];in[v]--;if(!in[v])q.push(v);}}bool flag=true;ans=0;for(int i=1;i<=num1+nb+na;i++){if(in[i]){flag=false;break;}ans=max(dis[i],ans);}if(!flag)printf("-1\n");else printf("%lld\n",ans);}return 0;
}