Luogu

LOJ

分析

容易想到一个图论模型,即从每个 A 类串向它所支配的 B 类串连边,从每个 B 类串向以它为前缀的 A 类串连边,并将所有 A 类串的权值设为长度。这样问题变为求最长路,如果有环输出 -1

第一类边可以直接连,但第二类边暴力连显然不行,考虑一些优化。

对反串建 SAM,此时 Parent 树上每个点的祖先都是它的前缀,于是我们只需要将树上每个 B 类串对应的节点向子树中所有 A 类串对应的节点连边。找某个子串在 SAM 上的点可以记一下每个后缀对应的点然后在 Parent 树上倍增。

进一步,我们可以在 Parent 树上从上往下连边,由 Parent 树上的节点连向 B 类串,再从 B 类串连向 Parent 树上的子节点和子节点包含的 A 类串。

然而这样子有一个问题,就是 SAM 上每个节点可能包含了多个 A 类串、B 类串。于是我们把每个节点对应的串按长度排序,如果长度相同则把 B 类串放在前面,然后依次扫过去,并记一个 $p$ 为之前扫到过的最后一个的 B 类串(没有扫到 B 类串时则为 SAM 上的节点),从 $p$ 向当前扫到的节点连边即可。连出来大概是一个这样的东西

X → A1,A2
↓
B1
↓
B2 → A3

最后的 $p$ 向 Parent 树上的子节点连边即可。

因为懒所以每次都暴力把整个数组清空了,于是跑得非常的慢。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define mset(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=800000+10;

int n,na,nb,m; char s[N];

namespace S {
    int lst,tot;
    int fa[N],ch[N][26],len[N],pos[N],f[20][N];
    void extend(int c) {
        int p=lst,np=++tot; lst=np,len[np]=len[p]+1;
        for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if (!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if (len[p]+1==len[q]) fa[np]=q;
            else {
                int nq=++tot; len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
    }
    int jump(int u,int l) {
        for (int i=19;~i;--i)
            if (len[f[i][u]]>=l) u=f[i][u];
        return u;
    }

    void clear() {
        mset(fa,0),mset(ch,0),mset(len,0),mset(pos,0),mset(f,0);
    }
}

int tot;
int ed[N],ida[N],idb[N],isa[N],len[N],deg[N];
ll dp[N];
vector<int> E[N],vs[N];
queue<int> Q;

int main() {
    int T=read();
    while (T--) {
        scanf("%s",s+1); n=strlen(s+1);
        S::lst=S::tot=1;
        for (int i=n;i;--i) S::extend(s[i]-'a'),S::pos[i]=S::lst;
        for (int i=1;i<=S::tot;++i) S::f[0][i]=S::fa[i];
        for (int i=1;i<=19;++i)
            for (int j=1;j<=S::tot;++j) S::f[i][j]=S::f[i-1][S::f[i-1][j]];
        tot=S::tot;
        na=read();
        for (int i=1;i<=na;++i) {
            int l=read(),r=read(),u=S::jump(S::pos[l],r-l+1);
            ida[i]=++tot,isa[tot]=1,len[tot]=r-l+1;
            vs[u].emplace_back(tot);
        }
        nb=read();
        for (int i=1;i<=nb;++i) {
            int l=read(),r=read(),u=S::jump(S::pos[l],r-l+1);
            idb[i]=++tot,isa[tot]=0,len[tot]=r-l+1;
            vs[u].emplace_back(tot);
        }
        m=read();
        for (int i=1;i<=m;++i) {
            int u=read(),v=read();
            E[ida[u]].emplace_back(idb[v]);
        }
        for (int i=1;i<=S::tot;++i) {
            sort(vs[i].begin(),vs[i].end(),[](int i,int j) {
                return len[i]<len[j]||(len[i]==len[j]&&!isa[i]&&isa[j]);
            });
            int p=i;
            for (int j:vs[i]) {
                E[p].emplace_back(j);
                if (!isa[j]) p=j;
            }
            ed[i]=p;
        }
        for (int i=2;i<=S::tot;++i) E[ed[S::fa[i]]].emplace_back(i);
        for (int i=1;i<=tot;++i)
            for (int j:E[i]) ++deg[j];
        for (int i=1;i<=tot;++i)
            if (!deg[i]) Q.push(i),dp[i]=isa[i]*len[i];
        while (!Q.empty()) {
            int u=Q.front(); Q.pop();
            for (int v:E[u]) {
                dp[v]=max(dp[v],dp[u]+isa[v]*len[v]);
                if (!--deg[v]) Q.push(v);
            }
        }
        int flag=0;
        for (int i=1;i<=tot;++i)
            if (deg[i]) { flag=1; break; }
        if (flag) puts("-1");
        else {
            ll ans=0;
            for (int i=1;i<=tot;++i) ans=max(ans,dp[i]);
            printf("%lld\n",ans);
        }

        S::clear();
        mset(ed,0),mset(ida,0),mset(idb,0),mset(isa,0),mset(len,0),mset(deg,0),mset(dp,0);
        for (int i=1;i<=tot;++i) E[i].clear();
        for (int i=1;i<=S::tot;++i) vs[i].clear();
    }
    return 0;
}
最后修改:2021 年 01 月 03 日 05 : 09 PM