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

原题传送门

我用sa做的本题 (码量似乎有点大)

先对原串建sa

考虑如何建图:

一开始每个以某个后缀都单独用一个链表存储。用merge函数依次将lcp为n~1的后缀的链表合并,当这个lcp为某个a串时候,在链表中插入a。当这个lcp为某个b串时候,以b开始的后缀所在的链表中的元素就是其所对应的a串(见merging函数)

现在每个b对应的a的编号都是链表中一段连续的区间

珂以用线段树优化建图

最后跑一下拓扑排序即可得出答案

#include <bits/stdc++.h>
#define N 1000005
#define M 16000005
#define ll long long
using namespace std;
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register ll x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline ll Max(register ll a,register ll b)
{
    return a>b?a:b;
}
struct edge{
    int to,next;
}e[M];
int head[N],cnte=1,degree[N],w[N],nt;
inline void add_edge(register int u,register int v)
{
    e[++cnte]=(edge){v,head[u]};
    head[u]=cnte;
    ++degree[v];
}
inline void cleargraph()
{
    memset(w,0,sizeof(w));
    memset(degree,0,sizeof(degree));
    memset(head,0,sizeof(head));
    cnte=1;
}
ll dp[N];
int q[N],qh,qt;
inline ll topsort()
{
    qh=qt=0;
    memset(dp,0,sizeof(dp));
    for(register int i=1;i<=nt;++i)
        if(!degree[i])
            q[++qt]=i;
    ll ans=0;
    while(qh<qt)
    {
        int u=q[++qh];
        dp[u]+=w[u];
        ans=Max(ans,dp[u]);
        for(register int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            dp[v]=Max(dp[v],dp[u]);
            if(!--degree[v])
                q[++qt]=v;	
        }
    }
    return qt<nt?-1LL:ans;
}
int n,sizem;
char s[N];
int rak[N],sa[N],tp[N],tex[N],height[N];
inline void Qsort()
{
    for(register int i=0;i<=sizem;++i)
        tex[i]=0;
    for(register int i=1;i<=n;++i)
        ++tex[rak[i]];
    for(register int i=1;i<=sizem;++i)
        tex[i]+=tex[i-1];
    for(register int i=n;i>=1;--i)
        sa[tex[rak[tp[i]]]--]=tp[i];
}
inline void sa_build()
{
    memset(tp,0,sizeof(tp));
    memset(rak,0,sizeof(rak));
    sizem=30;
    for(register int i=1;i<=n;++i)
        rak[i]=s[i]-'a'+1,tp[i]=i;
    Qsort();
    for(register int w=1,p=0;p<n;sizem=p,w<<=1)
    {
        p=0;
        for(register int i=1;i<=w;++i)
            tp[++p]=n-w+i;
        for(register int i=1;i<=n;++i)
            if(sa[i]>w)
                tp[++p]=sa[i]-w;
        Qsort();
        swap(tp,rak);
        rak[sa[1]]=p=1;
        for(register int i=2;i<=n;++i)
            rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
    }
}
inline void getheight()
{
    int k=0;
    for(register int i=1;i<=n;++i)
    {
        if(k)
            --k;
        int j=sa[rak[i]-1];
        while(s[i+k]==s[j+k])
            ++k;
        height[rak[i]]=k;
    }
}
struct Unionset{
    int f[N];
    inline void makeset(register int n)
    {
        for(register int i=1;i<=n;++i)
            f[i]=i;
    }
    inline int find(register int x)
    {
        return f[x]==x?f[x]:f[x]=find(f[x]);
    }
    inline void merge(register int x,register int y)
    {
        if(find(x)!=find(y))
            f[f[x]]=f[y];
    }
};
struct ListNode{
    int l,r;
    ListNode():l(-1),r(-1){}
};
ListNode* listNode=nullptr;
inline void clearListNodes()
{
    if(listNode!=nullptr) 
        delete[] listNode;
    listNode=new ListNode[N];
}
struct List{
    int head,tail;
    List():head(-1),tail(-1){}
    List(int node):head(node),tail(node){}
    List(int l,int r):head(l),tail(r){}
    List operator +(const List& other){
        if(tail==-1)
            return other;
        if(other.head==-1)
            return *this;
        listNode[tail].r=other.head;
        listNode[other.head].l=tail;
        return List(head,other.tail);
    }
};
int na,nb,la[N],ra[N],lb[N],rb[N];
List lst[N];
vector<int> merges[N],alen[N],blen[N];
Unionset us;
int invl[N],invr[N],ppos[N],seq[N];
inline void merging()
{
    clearListNodes();
    for(register int i=1;i<=n;++i)
        lst[i]=List();
    for(register int i=0;i<=n;++i)
    {
        merges[i].clear();
        alen[i].clear();
        blen[i].clear();
    }
    for(register int i=1;i<n;++i)
        merges[height[i+1]].push_back(i);
    for(register int i=1;i<=na;++i)
        alen[ra[i]-la[i]+1].push_back(i);
    for(register int i=1;i<=nb;++i)
        blen[rb[i]-lb[i]+1].push_back(i);
    us.makeset(n);
    for(register int len=n;len>=0;--len)
    {
        for(register int i=0;i<merges[len].size();++i)
        {
            int k=merges[len][i];
            int u=us.find(k),v=us.find(k+1);
            List tmp=lst[u]+lst[v];
            us.merge(u,v);
            lst[us.find(u)]=tmp;
        }
        for(register int i=0;i<alen[len].size();++i)
        {
            int a=alen[len][i];
            int u=us.find(rak[la[a]]);
            lst[u]=List(a)+lst[u];
        }
        for(register int i=0;i<blen[len].size();++i)
        {
            int b=blen[len][i];
            int v=us.find(rak[lb[b]]);
            invl[b]=Max(0,lst[v].head);
            invr[b]=Max(0,lst[v].tail);	
        }
    }
    for(register int i=1,u=lst[us.find(1)].head;i<=na;++i,u=listNode[u].r)
    {
        if(u==-1)
            break;
        seq[i]=u;
        ppos[u]=i;
    }
    ppos[0]=-1;
    for(register int i=1;i<=nb;++i)
    {
        invl[i]=ppos[invl[i]];
        invr[i]=ppos[invr[i]];
    }
}
inline void input()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    na=read();
    for(register int i=1;i<=na;++i)
        la[i]=read(),ra[i]=read();
    nb=read();
    for(register int i=1;i<=nb;++i)
        lb[i]=read(),rb[i]=read();
    cleargraph();
    int m=read();
    for(register int i=1;i<=m;++i)
    {
        int x=read(),y=read();
        add_edge(x,na+y);
    }
}
int tot=0,ls[N],rs[N];
inline void seg_build(register int &x,register int l,register int r)
{
    if(l==r)
    {
        x=seq[l];
        return;
    }
    else
        x=++tot;
    int mid=l+r>>1;
    seg_build(ls[x],l,mid);
    seg_build(rs[x],mid+1,r);
    add_edge(x,ls[x]),add_edge(x,rs[x]);
}
inline void seg_addedge(register int x,register int l,register int r,register int b,register int L,register int R)
{
    if(L<=l&&r<=R)
    {
        add_edge(b+na,x);
        return;
    }
    int mid=l+r>>1;
    if(L<=mid)
        seg_addedge(ls[x],l,mid,b,L,R);
    if(R>mid)
        seg_addedge(rs[x],mid+1,r,b,L,R);
}
inline void buildsegtr()
{
    tot=na+nb;
    int root;
    seg_build(root,1,na);
    for(register int i=1;i<=nb;++i)
    {
        if(invl[i]<0)
            continue;
        seg_addedge(root,1,na,i,invl[i],invr[i]);
    }
    nt=tot;
}
inline ll solve()
{
    input();
    sa_build();
    getheight();
    merging();
    buildsegtr();
    for(register int i=1;i<=na;++i)
        w[i]=ra[i]-la[i]+1;
    return topsort();
}
int T;
int main()
{
    T=read();
    while(T--)
        write(solve()),puts("");
    return 0;
}
posted @ 2019-04-09 18:18  JSOI爆零珂学家yzhang  阅读(380)  评论(0编辑  收藏  举报