zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
    
  • 相关阅读:
    快速幂模板
    部分有关素数的题
    POJ 3624 Charm Bracelet (01背包)
    51Nod 1085 背包问题 (01背包)
    POJ 1789 Truck History (Kruskal 最小生成树)
    HDU 1996 汉诺塔VI
    HDU 2511 汉诺塔X
    HDU 2175 汉诺塔IX (递推)
    HDU 2077 汉诺塔IV (递推)
    HDU 2064 汉诺塔III (递推)
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10678771.html
Copyright © 2011-2022 走看看