• [Tjoi2016&Heoi2016]字符串


    [Tjoi2016&Heoi2016]字符串

    题目

    佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CEO,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

    INPUT

    输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n

    OUTPUT

    对于每一次询问,输出答案。

    SAMPLE

    INPUT

    5 5
    aaaaa
    1 1 1 5
    1 5 1 1
    2 3 2 3
    2 4 2 3
    2 3 2 4

    OUTPUT

    1

    1

    2

    2

    2

    解题报告

    $SA$+主席树+二分答案

    显然这道题直接用$SA$是不太可行的,所以我们可以考虑把他转化成判定性问题,我们二分一个$mid$,判定该长度是否可行

    我们考虑$SA$的用法,若两子串有公共前缀,那么两子串中间的$height$必不为$0$

    那么用$RMQ$搞出当前可以扩展二分答案出的子串至最长,然后进行查询

    显然我们可以将$Rank$扔到主席树中,再去搞查询

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 inline int read(){
     6     int sum(0);
     7     char ch(getchar());
     8     for(;ch<'0'||ch>'9';ch=getchar());
     9     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
    10     return sum;
    11 }
    12 int n,m,q;
    13 char s[100005];
    14 int t1[100005],t2[100005],t3[100005],buc[100005];
    15 int sa[100005],rank[100005],height[100005],mn[100005][20];
    16 inline void Suffix(){
    17     int i,j,k(0),p(0),*x(t1),*y(t2),*t;
    18     for(i=0;i<=m;++i)buc[i]=0;
    19     for(i=1;i<=n;++i)++buc[x[i]=s[i]];
    20     for(i=1;i<=m;++i)buc[i]+=buc[i-1];
    21     for(i=n;i>=1;--i)sa[buc[x[i]]--]=i;
    22     for(j=1;p<n;j<<=1,m=p){
    23         for(p=0,i=n-j+1;i<=n;++i)y[++p]=i;
    24         for(i=1;i<=n;++i)
    25             if(sa[i]>j)
    26                 y[++p]=sa[i]-j;
    27         for(i=0;i<=m;++i)buc[i]=0;
    28         for(i=1;i<=n;++i)t3[i]=x[y[i]];
    29         for(i=1;i<=n;++i)++buc[t3[i]];
    30         for(i=1;i<=m;++i)buc[i]+=buc[i-1];
    31         for(i=n;i>=1;--i)sa[buc[t3[i]]--]=y[i];
    32         for(t=x,x=y,y=t,x[sa[1]]=1,p=1,i=2;i<=n;++i)
    33             x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+j]==y[sa[i-1]+j]))?p:++p;
    34     }
    35     for(i=1;i<=n;++i)rank[sa[i]]=i;
    36     for(i=1;i<=n;height[rank[i++]]=k)
    37         for(k?--k:0,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
    38 }
    39 inline void ST(){
    40     for(int i=1;i<=n;++i)
    41         mn[i][0]=height[i];
    42     for(int i=1;(1<<i)<=n;++i)
    43         for(int j=1;j+(1<<i)-1<=n;++j)
    44             mn[j][i]=min(mn[j][i-1],mn[j+(1<<i-1)][i-1]);
    45 }
    46 int cnt;
    47 int rt[100005],lch[2000005],rch[2000005],sum[2000005];
    48 inline void update(int &x,int las,int pos,int l,int r){
    49     x=++cnt;
    50 //  cout<<x<<' '<<las<<' '<<pos<<' '<<l<<' '<<r<<endl;
    51     lch[x]=lch[las];
    52     rch[x]=rch[las];
    53     sum[x]=sum[las]+1;
    54     if(l==r)
    55         return;
    56     int mid((l+r)>>1);
    57     if(pos<=mid)
    58         update(lch[x],lch[las],pos,l,mid);
    59     else
    60         update(rch[x],rch[las],pos,mid+1,r);
    61 }
    62 inline int query(int x,int y,int ll,int rr,int l,int r){
    63     if(ll<=l&&r<=rr)
    64         return sum[y]-sum[x];
    65     int mid((l+r)>>1);
    66     if(rr<=mid)
    67         return query(lch[x],lch[y],ll,rr,l,mid);
    68     if(mid<ll)
    69         return query(rch[x],rch[y],ll,rr,mid+1,r);
    70     return query(lch[x],lch[y],ll,mid,l,mid)+query(rch[x],rch[y],mid+1,rr,mid+1,r);
    71 }
    72 int main(){
    73     n=read(),q=read(),m=130;
    74     scanf("%s",s+1);
    75     Suffix();
    76     ST();
    77     for(int i=1;i<=n;++i)
    78         update(rt[i],rt[i-1],rank[i],1,n);
    79     while(q--){
    80         int a(read()),b(read()),c(read()),d(read());
    81         int l(1),r(min(b-a+1,d-c+1)),mid,ans=0;
    82         int tp(rank[c]);
    83         while(l<=r){
    84             mid=(l+r)>>1;
    85             int tp1(tp),tp2(tp);
    86             for(int i=16;i>=0;--i)
    87                 if(tp1>=(1<<i)&&mn[tp1-(1<<i)+1][i]>=mid)
    88                     tp1-=(1<<i);
    89             for(int i=16;i>=0;--i)
    90                 if(tp2+(1<<i)<=n&&mn[tp2+1][i]>=mid)
    91                     tp2+=(1<<i);//cout<<l<<' '<<r<<' '<<mid<<' '<<tp1<<" "<<tp2<<endl;
    92             if(query(rt[a-1],rt[b-mid+1],tp1,tp2,1,n)>0)
    93                 ans=mid,l=mid+1;
    94             else
    95                 r=mid-1;
    96         }
    97         printf("%d
    ",ans);
    98     }
    99 }
    View Code
  • 相关阅读:
    ajax提交转码解码
    关于idea开发工具常用的快捷键
    oracle 查询某个时间段数据
    hibernate : object references an unsaved transient instance 问题
    log4j日志
    JS关键字 import
    代码正常,junit却报错原因及解决方法
    hdu 5868 Polya计数
    hdu 5893 (树链剖分+合并)
    hdu 5895 广义Fibonacci数列
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7585538.html
Copyright © 2020-2023  润新知