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;
    }
    
  • 相关阅读:
    使用pthread_create时参数的传递
    借用 Google 构建自己的搜索系统
    编辑Servlet程序
    线程简单介绍
    Apache Tomcat服务器配置基础
    win2000server IIS和tomcat5多站点配置
    COmega 概述
    用Flash制作Google搜索程序
    浅析.Net下的多线程编程
    Mozilla宣布XForms开发项目 XForms是什么?它带来了什么?
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10678771.html
Copyright © 2011-2022 走看看