• [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树


    4556: [Tjoi2016&Heoi2016]字符串

    Time Limit: 20 Sec  Memory Limit: 128 MB

    Description

    佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
    一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
    O,嫁给高富帅,走上人生巅峰。每个问题均有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

    Sample Output

    1
    1
    2
    2
    2
     
    题解:
     真是太刺激了。。第一次发现后缀数组可以和高级数据结构联系起来233
    (不过据说正解并不是裸跑后缀数组……)
    首先,我们容易想到二分答案求解,但是二分之后怎么处理呢?
    我们考虑,对于这个二分的长度x,rank[c]附近一定可以形成一段区间,使得他们的lcp大于等于x(rank[c]自己的lcp是串长)
    这一段区间的查询我们可以通过ST表进行查询
    接下来,如果[a,b]范围内有一个串存在于那个区间里就好了,
    那么我们考虑,如何查询某个区间内的一些给定值是否出现某个值呢?
    这种查询的特点不难让我们想到主席树"切割区间"的功能:
    即查询a到b-x+1(如果x等于0,那么这个端点是b)区间内是否有一个rank值处在刚才查找到的区间,
    我们可以通过主席树这种权值线段树记录这个存在性问题
    这样不断判断合法性即可,复杂度是nlogn预处理+mlog2n查询的,因此可以AC.
    代码实现:
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 const int N=100010;
      6 int cnt[N],xx[N],yy[N],n;
      7 char s[N];
      8 int rank[N],sa[N],height[N],bin[20],f[N][18];
      9 inline void get_sa(int m)
     10 {
     11     int *x=xx,*y=yy;
     12     register int i,j,p,k;
     13     for(i=0;i<m;++i)cnt[i]=0;
     14     for(i=0;i<n;++i)++cnt[x[i]=s[i]];
     15     for(i=1;i<m;++i)cnt[i]+=cnt[i-1];
     16     for(i=n-1;~i;--i)sa[--cnt[x[i]]]=i;
     17     for(k=1,p=0;k<=n&&p<n;k<<=1,m=p)
     18     {
     19         for(p=0,i=n-k;i<n;++i)y[p++]=i;
     20         for(i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
     21         for(i=0;i<m;++i)cnt[i]=0;
     22         for(i=0;i<n;++i)++cnt[x[y[i]]];
     23         for(i=1;i<m;++i)cnt[i]+=cnt[i-1];
     24         for(i=n-1;~i;--i)sa[--cnt[x[y[i]]]]=y[i];
     25         swap(x,y),x[sa[0]]=0,p=1;
     26         for(i=1;i<n;++i)
     27             x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p-1:p++;
     28     }
     29 }
     30 inline void get_height()
     31 {
     32     register int i,j,k;
     33     for(i=0;i<n;++i)rank[sa[i]]=i;
     34     for(k=i=0;i<n;height[rank[i++]]=k)
     35         for(k=k?k-1:k,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
     36 }
     37 inline void ST()
     38 {
     39     register int i,j;
     40     for(bin[0]=i=1;i<=18;++i)
     41         bin[i]=bin[i-1]<<1;
     42     for(j=0;j<n;++j)f[j][0]=height[j];
     43     for(i=1;bin[i-1]<=n;++i)
     44         for(j=0;j+bin[i]<=n;++j)
     45             f[j][i]=min(f[j][i-1],f[j+bin[i-1]][i-1]);
     46 }
     47 struct node
     48 {
     49     node *ch[2];int cnt;
     50     node(){ch[0]=ch[1]=NULL;cnt=0;}
     51     inline void update(){cnt=ch[0]->cnt+ch[1]->cnt;}
     52 }*null=new node(),*root[N];
     53 inline node* newnode()
     54     {node *o=new node();o->ch[1]=o->ch[0]=null;return o;}
     55 inline bool query(node *a,node *b,int L,int R,int l,int r)
     56 {
     57     if(L<=l&&r<=R)return b->cnt-a->cnt;
     58     int mi=l+r>>1;bool ret=0;
     59     if(L<=mi)ret|=query(a->ch[0],b->ch[0],L,R,l,mi);
     60     if(mi<R)ret|=query(a->ch[1],b->ch[1],L,R,mi+1,r);
     61     return ret;
     62 }
     63 inline void get_range(int val,int &l,int &r)
     64 {
     65     register int j;
     66     for(j=17;~j&&r<n;--j)
     67         if(r+bin[j]-1<n&&f[r+1][j]>=val)r+=bin[j];
     68     for(j=17;~j&&l;--j)
     69         if(l-bin[j]+1>=0&&f[l-bin[j]+1][j]>=val)l-=bin[j];
     70 }
     71 inline bool judge(int a,int b,int c,int minimum)
     72 {
     73     int l=rank[c],r=rank[c],right=minimum?b-minimum+1:b;
     74     get_range(minimum,l,r);
     75     if(query(a?root[a-1]:null,root[right],l,r,0,n-1))return 1;
     76     return 0;
     77 }
     78 inline void insert(node *&o,node *old,int l,int r,int pos)
     79 {
     80     o->cnt=old->cnt+1;int mi=(l+r)>>1;if(l==r)return;
     81     if(pos<=mi)
     82         o->ch[1]=old->ch[1],o->ch[0]=newnode(),
     83         insert(o->ch[0],old->ch[0],l,mi,pos);
     84     else 
     85         o->ch[0]=old->ch[0],o->ch[1]=newnode(),
     86         insert(o->ch[1],old->ch[1],mi+1,r,pos);
     87     o->update();
     88 }
     89 inline void Tree_intn()
     90 {
     91     register int i;
     92     null->ch[0]=null->ch[1]=null;
     93     for(i=0;i<n;++i)root[i]=newnode();
     94     insert(root[0],null,0,n-1,rank[0]);
     95     for(i=1;i<n;++i)
     96         insert(root[i],root[i-1],0,n-1,rank[i]);
     97 }
     98 int main()
     99 {
    100     register int i,j,k,a,b,c,d,m,l,mi,r,ans;
    101     scanf("%d%d%s",&n,&m,s),s[n++]=1,
    102     get_sa(256),get_height(),ST(),Tree_intn();
    103     while(m--)
    104     {
    105         scanf("%d%d%d%d",&a,&b,&c,&d),--a,--b,--c,--d;
    106         l=0,mi,r=min(b-a+1,d-c+1),ans=0;
    107         while(l<=r)
    108             if(judge(a,b,c,(mi=l+r>>1)))l=mi+1,ans=mi;
    109             else r=mi-1;
    110         printf("%d
    ",ans);
    111     }
    112 }
  • 相关阅读:
    异常
    带参数的方法
    变量,基本类型,数据类型和运算符
    数据类型转换(针对数字类型)
    this关键字
    面向对象DAO模式
    常见类 Object
    方法和包
    final关键字
    abstract关键字
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7530903.html
Copyright © 2020-2023  润新知