zoukankan      html  css  js  c++  java
  • Luogu P5284 [十二省联考2019]字符串问题

    好难写的字符串+数据结构问题,写+调了一下午的说

    首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中(A)类串的点权为它们的长度,(B)类串的权值为(0)

    这样我们根据题意把(A o B)的边连起来,同时每个(B)类串向所有以其为前缀(A)类串连边

    这样我们就得到了一张DAG(如果不是的话就输出(-1)),然后对于它拓扑排序之后求权值和最大链即可

    但是第二类边该怎么连呢,下面我们来分析一下具体操作


    SA转化问题

    首先关于这种前后缀相关的问题,我们大可以利用SA来搞

    先对于原串建出SA,然后对于每一个(B)类串(b_i),我们找到(rk_{lb_{b_i}}),然后二分向两边扩展找出与它(operatorname{LCP}ge len_{b_i})的最大区间(可利用关于(operatorname{LCP})的定理证明单调性)

    然后我们直接从这个(B)类串向找到的区间连边?所以直接一发线段树优化建图就OK了?

    但是有一个问题,就是SA上的后缀长度和实际长度不相等,所以可能会出现(|A<|B|)的情况,此时显然(B)不能算作(A)的前缀

    所以我们要请出一个全新的技巧——主席树优化建图


    主席树优化建图

    由于这里最难处理的还是字符串长度,所以我们以此为版本建立主席树

    (A)类串的处理比较简单,我们可以直接从它对应版本对应(rk)的点向它连边

    然后对于(B)类串,向对应版本的区间连边,同时为了使复杂度不爆炸我们从父节点向子节点连边,这样区间连边的复杂度就是(log n)级别的

    然后对于主席树之间,我们从小到大连边,这样就保证了只能向长度更大的串走

    所以这道题顺利完成了


    复杂度分析

    首先由于这题中的各种东西都可以认为与(N)同阶,那么:

    总点数:(n+nlog n);总边数:(2n+4nlog n);总复杂度:(O(Tcdot nlog n))

    CODE

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    #define Ms(f,x) memset(f,x,sizeof(f))
    using namespace std;
    typedef long long LL;
    const int N=2e5+5,P=20,AN=(N<<1)+N*P,AM=(N<<1)+(N*P<<2);
    struct edge
    {
        int to,nxt;
    }e[AM]; int head[AN],cnt,tot,x,y; vector <int> v[N];
    char s[N]; int t,m,len,na,nb,la[N],ra[N],lb[N],rb[N];
    int deg[AN],rt[N],rt_[N],q[AN],val[AN]; long long f[AN];
    inline void add(CI x,CI y)
    {
        if (!y) return; e[++cnt]=(edge){y,head[x]}; head[x]=cnt; ++deg[y];
    }
    class President_Tree
    {
        private:
            int ch[AN][2],cur;
            inline int insert(CI lst,int &now,CI pos,CI l=1,CI r=len)
            {
                now=++tot; ch[tot][0]=ch[lst][0]; ch[tot][1]=ch[lst][1];
                add(now,lst); if (l==r) return now; int mid=l+r>>1,id;
                if (pos<=mid) id=insert(ch[lst][0],ch[now][0],pos,l,mid);
                else id=insert(ch[lst][1],ch[now][1],pos,mid+1,r);
                add(now,ch[now][0]); add(now,ch[now][1]); return id;
            }
        public:
            inline void clear(void)
            {
                for (RI i=1;i<=tot;++i) ch[i][0]=ch[i][1]=0; tot=cur=0;
            }
            inline int insert(CI len,CI pos)
            {
                ++cur; int id=insert(rt_[cur-1],rt_[cur],pos); rt[len]=rt_[cur]; return id;
            }
            #define O num,beg,end
            inline void link(CI now,CI num,CI beg,CI end,CI l=1,CI r=len)
            {
                if (!now) return; if (beg<=l&&r<=end) return add(num,now); int mid=l+r>>1;
                if (beg<=mid) link(ch[now][0],O,l,mid); if (end>mid) link(ch[now][1],O,mid+1,r);
            }
            #undef O
    }SEG;
    class Suffix_Array
    {
        private:
            int sa[N],t[N],bkt[N],hgt[N],log[N],f[N][P],size;
            inline void Radix_Sort(CI n)
            {
                RI i; for (i=0;i<=size;++i) bkt[i]=0;
                for (i=1;i<=n;++i) ++bkt[rk[i]];
                for (i=1;i<=size;++i) bkt[i]+=bkt[i-1];
                for (i=n;i;--i) sa[bkt[rk[t[i]]]--]=t[i];
            }
            inline void build(char *s,CI n)
            {
                RI i; for (size=122,i=1;i<=n;++i) rk[i]=s[i],t[i]=i;
                Radix_Sort(n); for (RI w=1,p=1;p<n;size=p,w<<=1)
                {
                    for (p=0,i=n-w+1;i<=n;++i) t[++p]=i;
                    for (i=1;i<=n;++i) if (sa[i]>w) t[++p]=sa[i]-w;
                    Radix_Sort(n); swap(rk,t); rk[sa[1]]=p=1;
                    for (i=2;i<=n;++i) rk[sa[i]]=(t[sa[i-1]]==t[sa[i]]&&t[sa[i-1]+w]==t[sa[i]+w])?p:++p;
                }
            }
            inline void get_height(char *s,CI n)
            {
                RI i,lst=0; for (i=1;i<=n;++i) rk[sa[i]]=i;
                for (i=1;i<=n;++i)
                {
                    if (rk[i]==1) continue; if (lst) --lst; int pos=sa[rk[i]-1];
                    while (pos+lst<=n&&i+lst<=n&&s[pos+lst]==s[i+lst]) ++lst; hgt[rk[i]]=lst;
                }
            }
            inline int min(CI a,CI b)
            {
                return a<b?a:b;
            }
            inline int LCP(int x,int y)
            {
                if (x>y) swap(x,y); ++x; int k=log[y-x+1];
                return min(f[x][k],f[y-(1<<k)+1][k]);
            }
        public:
            int rk[N];
            inline void init(char *s,CI n)
            {
                RI i; build(s,n); get_height(s,n);
                for (log[0]=-1,i=1;i<=n;++i) log[i]=log[i>>1]+1;
                for (i=1;i<=n;++i) f[i][0]=hgt[i];
                for (RI j=1;j<P;++j) for (i=1;i+(1<<j)-1<=n;++i)
                f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
            }
            inline void work(CI id)
            {
                int pos=rk[lb[id]],l,r,mid,nl=rb[id]-lb[id]+1,ret1=pos,ret2=pos;
                l=1; r=pos-1; while (l<=r) if (LCP(mid=l+r>>1,pos)>=nl) ret1=mid,r=mid-1; else l=mid+1;
                l=pos+1; r=len; while (l<=r) if (LCP(mid=l+r>>1,pos)>=nl) ret2=mid,l=mid+1; else r=mid-1;
                SEG.link(rt[nl],na+id,ret1,ret2);
            }
    }SA;
    inline void maxer(LL& x,const LL& y)
    {
        if (y>x) x=y;
    }
    #define to e[i].to
    inline LL Topo_Sort(LL ans=0)
    {
        RI H=0,T=0,i; for (i=1;i<=na;++i) f[i]=val[i]=ra[i]-la[i]+1;
        for (i=1;i<=tot;++i) if (!deg[i]) q[++T]=i; while (H<T)
        {
            int now=q[++H]; for (maxer(ans,f[now]),i=head[now];i;i=e[i].nxt)
            if (maxer(f[to],f[now]+val[to]),!--deg[to]) q[++T]=to;
        }
        return T!=tot?-1:ans;
    }
    #undef to
    inline void solve(void)
    {
        RI i; scanf("%s",s+1); len=strlen(s+1); SA.init(s,len);
        for (scanf("%d",&na),i=1;i<=na;++i)
        scanf("%d%d",&la[i],&ra[i]),v[ra[i]-la[i]+1].push_back(i);
        for (scanf("%d",&nb),i=1;i<=nb;++i) scanf("%d%d",&lb[i],&rb[i]);
        for (tot=na+nb,i=len;i;--i)
        {
            rt[i]=rt[i+1]; for (int it:v[i])
            add(SEG.insert(i,SA.rk[la[it]]),it);
        }
        for (i=1;i<=nb;++i) SA.work(i); for (scanf("%d",&m),i=1;i<=m;++i)
        scanf("%d%d",&x,&y),add(x,na+y); printf("%lld
    ",Topo_Sort());
    }
    inline void clear(void)
    {
        cnt=0; Ms(head,0); Ms(deg,0); SEG.clear(); Ms(f,0); Ms(val,0); 
        for (RI i=1;i<=len;++i) rt[i]=rt_[i]=0,v[i].clear();
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        for (scanf("%d",&t);t;--t) solve(),clear(); return 0;
    }
    
  • 相关阅读:
    【Uvalive4960】 Sensor network (苗条树,进化版)
    【UVA 1151】 Buy or Build (有某些特别的东东的最小生成树)
    【UVA 1395】 Slim Span (苗条树)
    【UVA 10600】 ACM Contest and Blackout(最小生成树和次小生成树)
    【UVA 10369】 Arctic Network (最小生成树)
    【UVA 10816】 Travel in Desert (最小瓶颈树+最短路)
    【UVA 11183】 Teen Girl Squad (定根MDST)
    【UVA 11865】 Stream My Contest (二分+MDST最小树形图)
    【UVA 11354】 Bond (最小瓶颈生成树、树上倍增)
    【LA 5713 】 Qin Shi Huang's National Road System (MST)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10751146.html
Copyright © 2011-2022 走看看