Luogu P5284 [十二省联考2019]字符串问题

Link
\(u\)支配\(v\)则连边\(A_u\rightarrow B_v\)
\(B_u\)\(A_v\)的前缀则连边\(B_u\rightarrow A_v\)
那么我们要求的就是这张图的点权最长路,拓扑排序+dp即可。
考虑如何优化建图。
先建出反串的SAM。
然后对于给定的子串\(s_{l,r}\),parent树上倍增找到它在SAM中的出现位置,然后把这个子串挂在SAM的这个点上。
注意到SAM上一个节点中的字符串在反串中互为后缀,因此它们在原串中互为前缀。
那么我们以结束位置为第一关键字,是否为\(A\)类子串(是为\(1\),不是为\(0\))为第二关键字对每个节点上的子串降序排序。
这样每一个\(B\)子串类子串要连向的就是这个节点上排在它后面的\(A\)类子串。
注意到我们要求的是最长路,因此只需要向后面第一个\(A\)类子串连边即可。

#include
#include
#include
#include
#include
#include
namespace IO
{
    char ibuf[(1<<26)+1],*iS=ibuf;
    void In(){fread(ibuf,1,1<<26,stdin);}
    int read(){int x=0;while(!isdigit(*iS))++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return x;}
    void gets(char*s){while(isspace(*iS))++iS;while(islower(*iS))*s++=*iS++;*s='\0';}
}
using i64=long long;
using IO::read;
const int N=200007;
int cnt,tot,now,link[N*2],len[N*4],trans[N*2][26],id[N],fa[20][N*2],a[N],b[N],is[N*4],las[N*2],in[N*4];
char str[N];i64 dis[N*4];
std::vectore[N*4],g[N*2];std::queueq;
void clear()
{
    for(int i=0;i<20;++i) memset(fa[i]+1,0,cnt<<2);
    for(int i=1;i<=cnt;++i) g[i].clear();
    for(int i=1;i<=tot;++i) e[i].clear();
    memset(trans[1],0,cnt*104),memset(is+1,0,tot<<2),memset(in+1,0,tot<<2),memset(dis+1,0,tot<<3),cnt=now=1;
}
void extend(int c)
{
    int p=now,q;len[now=++cnt]=len[p]+1;
    for(;p&&!trans[p][c];p=link[p]) trans[p][c]=now;
    if(!p) return link[now]=1,void();
    if(len[q=trans[p][c]]==len[p]+1) return link[now]=q,void();
    len[++cnt]=len[p]+1,memcpy(trans[cnt],trans[q],104),link[cnt]=link[q],link[q]=link[now]=cnt;
    for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cnt;
}
void getin(int flg)
{
    int l=read(),r=read()-l+1;l=id[l];
    for(int i=19;~i;--i) if(fa[i][l]&&len[fa[i][l]]>=r) l=fa[i][l];
    is[++tot]=flg,len[tot]=r,g[l].push_back(tot);
}
i64 toposort()
{
    i64 ans=0;
    for(int i=1;i<=tot;++i) if(!in[i]) q.push(i);
    for(int u;!q.empty();)
    {
    u=q.front(),q.pop(),ans=std::max(ans,dis[u]+len[u]);
    for(int v:e[u]) if(dis[v]=std::max(dis[v],dis[u]+len[u]),!--in[v]) q.push(v);
    }
    for(int i=1;i<=tot;++i) if(in[i]) return -1;
    return ans;
}
int main()
{
    IO::In();
    for(int T=read(),n,m,na,nb;T;--T)
    {
    clear(),IO::gets(str+1),n=strlen(str+1);
    for(int i=n;i;--i) extend(str[i]-'a'),id[i]=now;
    memcpy(fa[0]+1,link+1,cnt<<2),tot=cnt;
    for(int j=1;j<20;++j) for(int i=1;i<=cnt;++i) fa[j][i]=fa[j-1][fa[j-1][i]];
    na=read();for(int i=1;i<=na;++i) getin(1),a[i]=tot;
    nb=read();for(int i=1;i<=nb;++i) getin(0),b[i]=tot;
    for(int i=1;i<=cnt;++i) std::sort(g[i].begin(),g[i].end(),[](int i,int j){return len[i]

你可能感兴趣的:(Luogu P5284 [十二省联考2019]字符串问题)