• BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案


    Solution 1:

    后缀数组暴力大法好

    #include <map>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define ll long long
    #define mp make_pair
    #define maxn 300005
     
    struct Suffix_Array{
        int s[maxn];
        int tmp[maxn],rk[maxn],sa[maxn],cnt[maxn],h[maxn];
        void build(int n,int m)
        {
            int i,j,k; n++;
            F(i,0,2*n+5) tmp[i]=rk[i]=sa[i]=h[i]=0;
            F(i,0,m-1) cnt[i]=0;
            F(i,0,n-1) cnt[rk[i]=s[i]]++;
            F(i,1,m-1) cnt[i]+=cnt[i-1];
            F(i,0,n-1) sa[--cnt[rk[i]]]=i;
            for (int k=1;k<=n;k<<=1)
            {
                F(i,0,n-1){j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
                sa[tmp[cnt[0]=0]]=j=0;
                F(i,1,n-1)
                {
                    if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
                    sa[tmp[i]]=j;
                }
                memcpy(rk,sa,(n+1)*sizeof (int)); memcpy(sa,tmp,(n+1)*sizeof (int));
                if (j>=n-1) break;
            }
            for (i=k=0;i<n;h[rk[i++]]=k)
                for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
        }
        void work(int n,int m)
        {
            F(t,1,m)
            {
                int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d); a--;b--;c--;d--;
                int mx=0,mn=d-c+1,mid=rk[c];
                if (a<=c&&b>=c) mx=min(d-c+1,b-c+1);
                for (int i=mid;i>1;--i)
                {
                    if (mn<=mx) break;
                    mn=min(mn,h[i]);
                    if (sa[i-1]>=a&&sa[i-1]<=b)
                        mx=max(mx,min(mn,b-sa[i-1]+1));
                }
                mn=d-c+1;
                for (int i=mid+1;i<=n;++i)
                {
                    if (mn<=mx) break;
                    mn=min(mn,h[i]);
                    if (sa[i]>=a&&sa[i]<=b)
                        mx=max(mx,min(mn,b-sa[i]+1));
                }
                printf("%d
    ",mx);
            }
        }
    }SA;
     
    int n,m;
    char s[maxn];
     
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%s",s);
        F(i,0,n-1) SA.s[i]=s[i]-'a'+1; SA.s[n]=0;
        SA.build(n,30); SA.work(n,m);
    }
    

      

    Solution 2:

    后缀数组 二分答案 主席数 ST表

    每次询问二分答案,然后找出要匹配的串在SA中最左以及最右的位置,然后主席树判断即可。这样貌似是两个$log$

    可以在主席树上直接找前驱后继,然后ST表直接查询,然后就成了一个$log$

    我比较菜,写的是第一种。不过一次写对还是挺欣慰的,(废话,你慢慢写了3h)

    #include <map>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define mp make_pair
    #define maxn 200005
     
    namespace SA{
        int tmp[maxn],s[maxn],cnt[maxn],rk[maxn],sa[maxn],h[maxn];
        int st[maxn][21],_log[maxn];
        void build(int n,int m)
        {
            int i,j,k; n++;
            F(i,0,2*n+1) tmp[i]=rk[i]=sa[i]=h[i]=0;
            F(i,0,m-1) cnt[i]=0;
            F(i,0,n-1) cnt[rk[i]=s[i]]++;
            F(i,1,m-1) cnt[i]+=cnt[i-1];
            F(i,0,n-1) sa[--cnt[rk[i]]]=i;
            for (int k=1;k<=n;k<<=1)
            {
                F(i,0,n-1){j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
                sa[tmp[cnt[0]=0]]=j=0;
                F(i,1,n-1)
                {
                    if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
                    sa[tmp[i]]=j;
                }
                memcpy(rk,sa,(n+1)*sizeof(int)); memcpy(sa,tmp,(n+1)*sizeof(int));
                if (j>=n-1) break;
            }
            for (i=k=0;i<n;h[rk[i++]]=k) for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
            F(i,1,n-1) st[i][0]=h[i];
            F(i,2,n-1) _log[i]=_log[i>>1]+1;
            F(i,1,20) F(j,1,n-(1<<i)) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
        }
        int query(int a,int b,int n)
        {
            if (a==b) return n-sa[a]; a++;
            int tmp=_log[b-a+1];
            return min(st[a][tmp],st[b-(1<<tmp)+1][tmp]);
        }
        int lcp(int a,int b,int n)
        {
            a=rk[a],b=rk[b];
            if (a>b) swap(a,b); if (a==b) return n-sa[a];
            a++; int tmp=_log[b-a+1];
            return min(st[a][tmp],st[b-(1<<tmp)+1][tmp]);
        }
    }
     
    namespace PT{
        int ls[maxn<<4],rs[maxn<<4],sum[maxn<<4],rt[maxn],tot=0;
        void modify(int o1,int & o2,int l,int r,int X,int f)
        {
            o2=++tot;sum[o2]=sum[o1]+f;if (l==r) return ;int mid=l+r>>1;
            if (X<=mid) rs[o2]=rs[o1],modify(ls[o1],ls[o2],l,mid,X,f);
            else ls[o2]=ls[o1],modify(rs[o1],rs[o2],mid+1,r,X,f);
        }
        int query(int o1,int o2,int l,int r,int L,int R)
        {
            if (L<=l&&r<=R) return sum[o2]-sum[o1];
            int mid=l+r>>1,ret=0;
            if (L<=mid) ret+=query(ls[o1],ls[o2],l,mid,L,R);
            if (R>mid) ret+=query(rs[o1],rs[o2],mid+1,r,L,R);
            return ret;
        }
    }
     
    int n,m;char s[maxn];
     
    bool check(int l,int r,int x,int mid)
    {
        int pos=SA::rk[x]; //printf("The Postion is %d
    ",pos);
        int ll=1,rr=pos,posl,posr;
        while (ll<rr)
        {
            int mmiidd=(ll+rr)/2;
            if (SA::query(mmiidd,pos,n)>=mid) rr=mmiidd;
            else ll=mmiidd+1;
        }
        posl=rr;
        ll=pos,rr=n;
        while (ll<rr)
        {
            int mmiidd=(ll+rr)/2+1;
            if (SA::query(pos,mmiidd,n)>=mid) ll=mmiidd;
            else rr=mmiidd-1;
        }
        posr=ll;
        if (PT::query(PT::rt[l-1],PT::rt[r],1,n,posl,posr)) return true;
        else return false;
    }
     
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%s",s); F(i,0,n-1) SA::s[i]=s[i]-'a'+1; SA::s[n]=0;
        SA::build(n,30);
        F(i,0,n-1)
        {
            PT::modify(PT::rt[i-1],PT::rt[i],1,n,SA::rk[i],1);
        }
        F(i,1,m)
        {
            int a,b,c,d,mx;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            a--;b--;c--;d--;
            if (a<=c&&c<=b) mx=min(b-c+1,d-c+1); else mx=0;
            int l=mx,r=min(d-c+1,b-a+1);
            while (l<r)
            {
                int mid=(l+r)/2+1;
                if (check(a,b-mid+1,c,mid)) l=mid;
                else r=mid-1;
            }
            printf("%d
    ",l);
        }
    }
    

      

  • 相关阅读:
    scala安装使用-01
    Java基础知识强化103:Java常量池理解与总结
    C笔记01:关于printf函数输出先后顺序的讲解
    Android进阶笔记13:ListView篇之ListView刷新显示(全局 和 局部)
    Android进阶笔记12:ListView篇之图片优化
    MySQL(19):SQL语句(MySQL)大全
    Android 高级UI设计笔记09:Android实现无限滚动列表
    Android进阶笔记11:ListView篇之ListView性能优化
    1. Android 系统上一款开源的图表库
    Java基础知识强化之网络编程笔记25:Android网络通信之 Future接口介绍(Java程序执行超时)
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6737896.html
Copyright © 2020-2023  润新知