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

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

\(SAM\)+拓扑

回来赶一篇博客吧。

\(SAM\)简单题。

很容易发现,对于一个串\(A_i\)对应的\(B\)集合中每一个\(B_j\),都能使得\(A_i\)转移到含有前缀\(B_j\)的串\(A_k\),如果出现了正环,那么答案必然是无限的,同时我们建立的图中不含有负权边,我们可以直接判断边集中是否有环即可,这可以用\(Tarjan\)线性完成。

如何找到含有一个串\(T\)的前缀的所有\(A_i\)串?我们考虑对反串建立\(SAM\),那么需要满足\(T\)\(A_i\)的后缀,找到\(T\)所在的节点,他的\(parent\)树上子树就是满足条件的\(A\)串。

其实我们只需要向其子树连一条\(0\)边即可,注意一个节点包含一个长度区间内的串,我们可以考虑进行拆点,那么直接跑最长路即可。

我好像没有发现这一点,结果对着\(parent\)树的\(dfn\)序来了一个线段树优化建图。

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#define N 200005
#define M 4000005
#define ll long long
#define IT vector<node> :: iterator
using namespace std;
int T;
int n,na,nb,m,x,y,l,r,ed[N];
int A[N],B[N],val[N];
int tot=1,lst=1,tr[N << 1][26],len[N << 1],pre[N << 1];
char s[N];
struct edge
{
    int nxt,v;
    edge (int Nxt=0,int V=0)
    {
        nxt=Nxt,v=V;
    }
}e[N << 1];
int tt,fr[N << 1];
int f[N << 1][22];
int cnt,dfn[N],rdfn[N];
int idfn[N],odfn[N];
struct node
{
    int op,len,id;
    node (int O=0,int L=0,int I=0)
    {
        op=O,len=L,id=I;
    }
    bool operator < (const node &A) const
    {
        if (len!=A.len)
            return len<A.len;
        return op>A.op;
    }
};
vector<node>E[N << 1];
struct Cedge
{
    int nxt,v,cost;
    Cedge (int Nxt=0,int V=0,int Cost=0)
    {
        nxt=Nxt,v=V,cost=Cost;
    }
}se[(N << 2)+M];
int mxp,pt[N];
int stt,sfr[N << 2],rd[N << 2];
bool flag=true,vis[N << 2],insta[N << 2];
ll ans=0,dis[N << 2];
queue<int>q;
void ins(int c,int I)
{
    int p=lst,q,np;
    ed[I]=lst=np=++tot;
    len[np]=len[p]+1;
    for (;p && !tr[p][c];p=pre[p])
        tr[p][c]=np;
    if (!p)
        pre[np]=1; else
        {
            q=tr[p][c];
            if (len[p]+1==len[q])
                pre[np]=q; else
                {
                    int g=++tot;
                    memcpy(tr[g],tr[q],sizeof(tr[q]));
                    len[g]=len[p]+1,pre[g]=pre[q];
                    for (;p && tr[p][c]==q;p=pre[p])
                        tr[p][c]=g;
                    pre[np]=pre[q]=g;
                }
        }   
}
void add(int x,int y)
{
    ++tt;
    e[tt]=edge(fr[x],y),fr[x]=tt;
}
void sadd(int x,int y,int z)
{
    ++stt;
    se[stt]=Cedge(sfr[x],y,z),sfr[x]=stt;
    ++rd[y];
}
void dfs(int u)
{
    for (int i=fr[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        f[v][0]=u;
        dfs(v);
    }
}
void GetDfn(int u)
{
    sort(E[u].begin(),E[u].end());
    for (IT it=E[u].begin();it!=E[u].end();++it)
        if (it->op==1)
        {
            dfn[++cnt]=it->id;
            rdfn[it->id]=cnt;
        } else
            idfn[it->id]=cnt+1;
    for (int i=fr[u];i;i=e[i].nxt)
    {
        int v=e[i].v;
        GetDfn(v);
    }
    for (IT it=E[u].begin();it!=E[u].end();++it)
        if (it->op==2)
            odfn[it->id]=cnt;
}
void build(int p,int l,int r)
{
    mxp=max(mxp,p);
    if (l==r)
    {
        pt[dfn[l]]=p;
        return;
    }
    int mid=(l+r) >> 1;
    build(p << 1,l,mid);
    build(p << 1 | 1,mid+1,r);
    if (l==mid)
        sadd(p,p << 1,val[dfn[l]]); else
        sadd(p,p << 1,0);
    if (mid+1==r)
        sadd(p,p << 1 | 1,val[dfn[r]]); else
        sadd(p,p << 1 | 1,0);
}
void link(int p,int l,int r,int x,int y,int z)
{
    if (l==x && r==y)
    {
        if (l==r)
            sadd(z,p,val[dfn[l]]); else
            sadd(z,p,0);
        return;
    }
    int mid=(l+r) >> 1;
    if (y<=mid)
        link(p << 1,l,mid,x,y,z); else
    if (x>mid)
        link(p << 1 | 1,mid+1,r,x,y,z); else
        {
            link(p << 1,l,mid,x,mid,z);
            link(p << 1 | 1,mid+1,r,mid+1,y,z);
        }
}
void Tarjan(int u)
{
    vis[u]=insta[u]=true;
    for (int i=sfr[u];i && flag;i=se[i].nxt)
    {
        int v=se[i].v;
        if (!vis[v])
            Tarjan(v); else
        if (insta[v])
        {
            flag=false;
            return;
        }
    }
    insta[u]=false;
}
void Topo()
{
    if (mxp==1)
        dis[1]=val[1];
    for (int i=1;i<=mxp;++i)
        if (!rd[i])
            q.push(i);
    while (!q.empty())
    {
        int u=q.front();
        q.pop();
        for (int i=sfr[u];i;i=se[i].nxt)
        {
            int v=se[i].v,cost=se[i].cost;
            dis[v]=max(dis[v],dis[u]+cost);
            --rd[v];
            if (!rd[v])
                q.push(v);
        }
    }
}
void Clear()
{
    memset(tr,0,26*(tot+1)*sizeof(int));
    memset(fr,0,(tot+1)*sizeof(int));
    memset(sfr,0,(mxp+1)*sizeof(int));
    memset(vis,0,(mxp+1)*sizeof(bool));
    memset(insta,0,(mxp+1)*sizeof(bool));
    memset(dis,0,(mxp+1)*sizeof(ll));
    memset(rd,0,(mxp+1)*sizeof(int));
    for (int i=1;i<=tot;++i)
        E[i].clear();
    flag=true;
    stt=tt=cnt=mxp=0;
    tot=lst=1;
    ans=0;
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        reverse(s+1,s+n+1);
        for (int i=1;i<=n;++i)
            ins(s[i]-'a',i);
        for (int i=2;i<=tot;++i)
            add(pre[i],i);
        dfs(1);
        for (int j=1;j<=20;++j)
            for (int i=1;i<=tot;++i)
                f[i][j]=f[f[i][j-1]][j-1];
        scanf("%d",&na);
        for (int i=1;i<=na;++i)
        {
            scanf("%d%d",&l,&r);
            l=n-l+1,r=n-r+1,swap(l,r);
            int k=ed[r];
            for (int j=20;j>=0;--j)
                if (f[k][j] && r-len[pre[f[k][j]]]<l)
                    k=f[k][j];
            if (r-len[pre[k]]<l)
                k=f[k][0];
            A[i]=k,val[i]=r-l+1;
            E[k].push_back(node(1,r-l+1,i));
        }
        scanf("%d",&nb);
        for (int i=1;i<=nb;++i)
        {
            scanf("%d%d",&l,&r);
            l=n-l+1,r=n-r+1,swap(l,r);
            int k=ed[r];
            for (int j=20;j>=0;--j)
                if (f[k][j] && r-len[pre[f[k][j]]]<l)
                    k=f[k][j];
            if (r-len[pre[k]]<l)
                k=f[k][0];
            B[i]=k;
            E[k].push_back(node(2,r-l+1,i));
        }
        GetDfn(1);
        build(1,1,na);
        scanf("%d",&m);
        for (int i=1;i<=m;++i)
        {
            scanf("%d%d",&x,&y);
            if (idfn[y]<=odfn[y])
                link(1,1,na,idfn[y],odfn[y],pt[x]);
        }
        for (int i=1;i<=mxp && flag;++i)
            if (!vis[i])
                Tarjan(i);
        if (flag)
        {
            Topo();
            for (int i=1;i<=mxp;++i)
                ans=max(ans,dis[i]);
            printf("%lld\n",ans);
        } else
            puts("-1");
        Clear();
    }
    return 0;
}
posted @ 2020-11-19 21:23  GK0328  阅读(95)  评论(0编辑  收藏  举报