[十二省联考2019]字符串问题 后缀自动机_拓扑排序_最长路_倍增
真的不太好写,一定要开 long long
Code:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#define setIO(s) freopen(s".in","r",stdin)// ,freopen(s".out","w",stdout)
#define maxn 1500001
using namespace std;
char str[maxn];
int debug;
int length,na,nb,m;
namespace SAM{
#define N 29
#define ll long long
#define L l=length-l+1
#define R r=length-r+1
int last,tot;
vector<int>ed[maxn];
int la[maxn],ra[maxn],h[maxn];
int ch[maxn][N],dis[maxn];
int f[maxn],trace[maxn],mk[maxn],pos[maxn];
int F[24][maxn];
int head[maxn],to[maxn],nex[maxn],edges;
int ge[maxn];
int vis[maxn];
int trc;
queue<int>Q;
int du[maxn];
long long DP[maxn];
int idx[maxn];
int cmp(int i,int j){ if(h[i]==h[j]) return i>j; return h[i]<h[j]; }
void add(int u,int v){
nex[++edges] = head[u],head[u]=edges,to[edges]=v;
mk[edges]=0;
//if(!debug) printf("%d %d\n",u,v);
}
//SAM of S
void ins(int c,int i){
int np = ++tot, p = last; last = np; dis[np] = i;
while(p && !ch[p][c]) ch[p][c] = np, p = f[p];
if(!p) f[np] = 1;
else {
int q = ch[p][c];
if(dis[q] == dis[p] + 1) f[np] = q;
else {
int nq = ++tot;
dis[nq] = dis[p] + 1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
f[nq] = f[q], f[np] = f[q] = nq;
while(p && ch[p][c] == q) ch[p][c] = nq,p = f[p];
}
}
trace[i] = np;
}
void DFS(int u){
F[0][u]=f[u];
for(int i=1;i<24;++i) F[i][u]=F[i-1][F[i-1][u]];
int sz=ed[u].size();
for(int i=0;i<sz;++i) DFS(ed[u][i]);
ed[u].clear();
}
void build(){
int l,r;scanf("%d",&na);
for(int i=1;i<=na;++i){
scanf("%d%d",&l,&r); L;R; swap(l,r);
la[i]=l,ra[i]=r,h[i]=r-l+1;
} scanf("%d",&nb);
for(int i=1;i<=nb;++i) {
scanf("%d%d",&l,&r); L;R; swap(l,r);
la[i+na]=l,ra[i+na]=r,h[i+na]=r-l+1;
}for(int i=2;i<=tot;++i) ed[f[i]].push_back(i);
trc=tot;
DFS(1);
for(int i=1;i<=na+nb;++i) {
int p=trace[ra[i]];
for(int j=23;j>=0;--j)
if(dis[F[j][p]] >= h[i])
p=F[j][p];
if(dis[p]==h[i])
pos[i]=p;
else
ed[p].push_back(i);
}
}
void sol(){
int nn=tot;
for(int i=2;i<=nn;++i){
if(ed[i].size()==0){
add(f[i],i);
continue;
}
int p=0;
int sz=ed[i].size();
for(int j=0;j<sz;++j) ge[++p]=ed[i][j]; //
sort(ge+1,ge+1+p,cmp); //将该点对应字符串按长度排序
int lst=f[i];
for(int j=1;j<=p;++j) {
add(lst,++tot);
dis[tot] = h[ge[j]];
pos[ge[j]]=tot;
lst=tot;
}
add(pos[ge[p]],i);
ed[i].clear();
}
}
void get(){
int a,b;
scanf("%d%d",&a,&b);
add(pos[a],pos[b+na]);
mk[edges]=1;
}
void solve(){
Q.push(1);
du[1]=0;
long long ans=0;
for(int i=1;i<=edges;++i) ++du[to[i]];
while(!Q.empty()){
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=nex[i]){
--du[to[i]];
long long ed=DP[u]+dis[to[i]]-(mk[i]?0:dis[u]);
DP[to[i]]=max(DP[to[i]],ed);
if(du[to[i]]==0) Q.push(to[i]);
}
}
for(int i=1;i<=tot;++i) if(du[i]!=0) {
printf("-1\n");
return;
}
for(int i=1;i<=na;++i) ans=max(ans,DP[pos[i]]);
printf("%lld\n",ans);
}
void init(){
for(int i=1;i<=tot;++i) DP[i]=0;
for(int i=1;i<=tot;++i) dis[i]=0;
for(int i=1;i<=edges;++i) mk[i]=0;
for(int i=1;i<=tot;++i) head[i]=0;
for(int i=0;i<=tot;++i) du[i]=0;
for(int i=1;i<=trc;++i) for(int j=0;j<=22;++j) F[j][i]=0;
for(int i=1;i<=trc;++i) memset(ch[i],0,sizeof(ch[i]));
last=tot=1,edges=0;
}
};
int main(){
//setIO("string9");
int T;
scanf("%d",&T);
while(T--){
debug=T;
SAM::last=SAM::tot=1;
scanf("%s",str+1),length=strlen(str+1);
for(int i=length;i;--i) SAM::ins(str[i]-'a',length-i+1);
SAM::trc=SAM::tot;
SAM::build();
SAM::sol();
scanf("%d",&m);
for(int i=1;i<=m;++i) SAM::get();
SAM::solve();
SAM::init();
}
return 0;
}