首先顯然能夠把具備支配關係的串從\(A\)到\(B\)連一條有向邊,若是\(B_i\)是\(A_j\)的前綴,就從\(B\)連一條邊到\(A\)。這樣子問題就轉化成了要求解這個二分圖的最長路經,有環答案就是\(-1\)。
而後顯然就是要找個什麼東西出來優化連邊是吧。。。
如今惟一要處理的東西就是要找到個啥玩意,來優化這個知足前綴條件的連邊。
僞裝咱們有一個全部後綴都被插進去的\(Trie\)樹,那麼對於每個\(B\)只須要找到其對應的節點,而後它子樹中的每個\(A\)都會被他連過去,這樣子彷佛就達成了優化連邊,即每個\(B\)連向這個節點,而後這樣節點連向在這個節點終止的\(A\)。
這個複雜度顯然是爆炸的,因此咱們能夠直接創建後綴樹,這樣子節點數就被優化到了\(O(n)\)級別。
因而問題又出現了,在後綴樹上的一個節點表示的長度是一段區間,假如一個節點上又掛了\(A\),又掛了\(B\)就會出鍋。(雖然無論這個也有\(80\)分了)
那行啊,咱們來拆個點,每一個樹上節點拆兩個,一個\(u\)負責掛好全部兒子,另一個\(v\)負責掛好全部在這個點的\(A\),而後全部的\(A\)按照長度從小往大掛成一條鏈。而後\(v\)指向\(u\),這樣子任何一個\(B\)對應的必定是一段後綴\(A\),因此直接後綴優化連邊連向這條鏈,而後再連向\(u\)表示指向全部的兒子。
這樣子仍是很麻煩,實際上有一個更加優秀的作法,就是對於一個點若是掛了多個串,那麼就按照每一個串長把這個點強行拆掉就好了(雖然本質上就是掛了一條鏈)。
因而只須要求解最長路就好了,並且仍是樹上的最長鏈,只須要按照拓撲序作就好了,即便有環也能夠在這個過程當中處理掉。ios
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; #define ll long long #define MAX 800800 #define pb push_back inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } vector<int> E[MAX],W[MAX],str[MAX]; char ch[MAX];int Len; int fa[20][MAX],pos[MAX],val[MAX]; struct Node{int son[26],len,ff;void clear(){memset(son,0,sizeof(son));len=ff=0;}}t[MAX]; int last=1,tot=1; void extend(int c) { int p=last,np=++tot;last=np; t[np].len=t[p].len+1; while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff; if(!p)t[np].ff=1; else { int q=t[p].son[c]; if(t[q].len==t[p].len+1)t[np].ff=q; else { int nq=++tot; t[nq]=t[q];t[nq].len=t[p].len+1; t[q].ff=t[np].ff=nq; while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff; } } } vector<int> ee[MAX]; void dfs(int u,int ff) { fa[0][u]=ff; for(int i=1;i<20;++i)fa[i][u]=fa[i-1][fa[i-1][u]]; for(int i=0,l=ee[u].size();i<l;++i)dfs(ee[u][i],u); } void Work() { Len=strlen(ch+1); for(int i=Len;i;--i)extend(ch[i]-97),pos[i]=last; for(int i=1;i<=tot;++i)ee[t[i].ff].pb(i); dfs(1,0); } int TOT,nd[MAX],IDA[MAX],IDB[MAX],Lim[MAX],lenA[MAX]; void Add(int u,int v,int w){if(u)E[u].pb(v),W[u].pb(w);} bool cmp(int a,int b){return lenA[a]<lenA[b];} void Build(int u,int ff) { int np=++TOT;nd[u]=np;Lim[np]=t[u].len; if(ff) { int lst=ff; for(int i=0,l=str[u].size();i<l;++i) { Add(lst,++TOT,0),val[TOT]=lenA[str[u][i]],fa[0][TOT]=lst,Lim[TOT]=lenA[str[u][i]],lst=TOT; IDA[str[u][i]]=TOT; } Add(lst,np,0);fa[0][np]=lst; } for(int i=0,l=ee[u].size();i<l;++i)Build(ee[u][i],np); } int deg[MAX];ll dis[MAX],ans; void Topsort() { for(int i=1;i<=TOT;++i) for(int j=0,l=E[i].size();j<l;++j) deg[E[i][j]]+=1; queue<int> Q;int QwQ=0; for(int i=1;i<=TOT;++i)if(!deg[i])Q.push(i); while(!Q.empty()) { int u=Q.front();Q.pop();QwQ+=1; ans=max(ans,dis[u]+val[u]); for(int i=0,l=E[u].size();i<l;++i) { int v=E[u][i]; dis[v]=max(dis[v],dis[u]+W[u][i]); if(!--deg[v])Q.push(v); } } if(QwQ<TOT)puts("-1"); else printf("%lld\n",ans); } int main() { int T=read(); while(T--) { scanf("%s",ch+1); Work(); int A=read(); for(int i=1;i<=A;++i) { int l=read(),r=read(),len=r-l+1; int u=pos[l];lenA[i]=len; for(int i=19;~i;--i) if(t[fa[i][u]].len>=len)u=fa[i][u]; str[u].pb(i); } for(int i=1;i<=tot;++i)sort(str[i].begin(),str[i].end(),cmp); for(int i=0;i<=tot;++i) for(int j=0;j<20;++j)fa[j][i]=0; Build(1,0); for(int j=1;j<20;++j) for(int i=1;i<=TOT;++i) fa[j][i]=fa[j-1][fa[j-1][i]]; int B=read(); for(int i=1;i<=B;++i) { int l=read(),r=read(),len=r-l+1;IDB[i]=++TOT; int u=nd[pos[l]]; for(int j=19;~j;--j) if(Lim[fa[j][u]]>=len)u=fa[j][u]; Add(IDB[i],u,0); } int C=read(); while(C--) { int x=read(),y=read(); Add(IDA[x],IDB[y],lenA[x]); } Topsort(); for(int i=0;i<=TOT;++i) { ee[i].clear();E[i].clear();t[i].clear(); str[i].clear();W[i].clear(); for(int j=0;j<20;++j)fa[j][i]=0; IDA[i]=IDB[i]=Lim[i]=pos[i]=deg[i]=0; dis[i]=ans=val[i]=lenA[i]=nd[i]=0; } last=tot=1;TOT=0; } return 0; }