BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

Description

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为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

Sample Output

1
1
2
2
2

Solution

设$suf_i$表示后缀$i$,

首先考虑二分一个答案$mid$,那么现在问题转化成求$suf_a$到$suf_{b-mid+1}$的这些个后缀中,是否有一个后缀和$suf(c)$的$lcp$大于等于$mid$。

设$SA_i$表示后缀排序排名为$i$的后缀,$Rank_i$表示$suf_i$的后缀排序排名。

由于对于$suf_c$,我们可以用二分+$ST$表求出后缀排序中的可行区间,可行区间内的后缀和$suc_c$的$lcp$长度都大于等于$mid$。现在问题转化为了求$suf_a$到$suf_{b-mid+1}$的这些后缀是否哪个后缀的$Rank$值在可行区间内,这个用一个主席树就好了。

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N (100009)
  5 using namespace std;
  6 
  7 struct Sgt{int ls,rs,val;}Segt[N*18];
  8 int Root[N],sgt_num;
  9 int n,q,m=26,a,b,c,d;
 10 int ST[N][18],LOG2[N];
 11 int wa[N],wb[N],wt[N],SA[N],Height[N],Rank[N];
 12 char r[N];
 13 
 14 inline int read()
 15 {
 16     int x=0,w=1; char c=getchar();
 17     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
 18     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
 19     return x*w;
 20 }
 21 
 22 bool cmp(int *y,int a,int b,int k)
 23 {
 24     int arank1=y[a];
 25     int brank1=y[b];
 26     int arank2=a+k>=n?-1:y[a+k];
 27     int brank2=b+k>=n?-1:y[b+k];
 28     return arank1==brank1 && arank2==brank2;
 29 }
 30 
 31 void Build_SA()
 32 {
 33     int *x=wa,*y=wb;
 34     for (int i=0; i<m; ++i) wt[i]=0;
 35     for (int i=0; i<n; ++i) ++wt[x[i]=r[i]-'a'];
 36     for (int i=1; i<m; ++i) wt[i]+=wt[i-1];
 37     for (int i=n-1; i>=0; --i) SA[--wt[x[i]]]=i;
 38     
 39     for (int j=1; j<=n; j<<=1)
 40     {
 41         int p=0;
 42         for (int i=n-j; i<n; ++i) y[p++]=i;
 43         for (int i=0; i<n; ++i) if (SA[i]>=j) y[p++]=SA[i]-j;
 44         
 45         for (int i=0; i<m; ++i) wt[i]=0;
 46         for (int i=0; i<n; ++i) ++wt[x[y[i]]];
 47         for (int i=1; i<m; ++i) wt[i]+=wt[i-1];
 48         for (int i=n-1; i>=0; --i) SA[--wt[x[y[i]]]]=y[i];
 49 
 50         m=1; swap(x,y);
 51         x[SA[0]]=0;
 52         for (int i=1; i<n; ++i)
 53             x[SA[i]]=cmp(y,SA[i],SA[i-1],j)?m-1:m++;
 54         if (m>=n) break;
 55     }
 56 }
 57 
 58 void Build_Height()
 59 {
 60     for (int i=0; i<n; ++i) Rank[SA[i]]=i;
 61     int k=0;
 62     for (int i=0; i<n; ++i)
 63     {
 64         if (!Rank[i]) continue;
 65         if (k) k--;
 66         int j=SA[Rank[i]-1];
 67         while (r[i+k]==r[j+k]) ++k;
 68         Height[Rank[i]]=k;
 69     }
 70 }
 71 
 72 void Build_ST()
 73 {
 74     for (int i=2; i<=n; ++i) LOG2[i]=LOG2[i>>1]+1;
 75     for (int i=0; i<n; ++i) ST[i][0]=Height[i];
 76     for (int j=1; j<=17; ++j)
 77         for (int i=0; i+(1<<j)-1<n; ++i)
 78             ST[i][j]=min(ST[i][j-1],ST[i+(1<<j-1)][j-1]);
 79 }
 80 
 81 int Query(int l,int r)
 82 {
 83     int k=LOG2[r-l+1];
 84     return min(ST[l][k],ST[r-(1<<k)+1][k]);
 85 }
 86 
 87 int Update(int pre,int l,int r,int x)
 88 {
 89     int now=++sgt_num;
 90     Segt[now]=Segt[pre];
 91     Segt[now].val++;
 92     if (l==r) return now;
 93     int mid=(l+r)>>1;
 94     if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
 95     else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x);
 96     return now;
 97 }
 98 
 99 int Query(int u,int v,int l,int r,int l1,int r1)
100 {
101     if (l>r1 || r<l1) return 0;
102     if (l1<=l && r<=r1) return Segt[v].val-Segt[u].val;
103     int mid=(l+r)>>1;
104     return Query(Segt[u].ls,Segt[v].ls,l,mid,l1,r1)+Query(Segt[u].rs,Segt[v].rs,mid+1,r,l1,r1);
105 }
106 
107 bool check(int lim)
108 {
109     int l,r,L,R;
110     l=0,r=Rank[c]-1,L=Rank[c];
111     while  (l<=r)
112     {
113         int mid=(l+r)>>1;
114         if (Query(mid+1,Rank[c])>=lim) L=mid,r=mid-1;
115         else l=mid+1;
116     }
117     l=Rank[c]+1,r=n-1,R=Rank[c];
118     while (l<=r)
119     {
120         int mid=(l+r)>>1;
121         if (Query(Rank[c]+1,mid)>=lim) R=mid,l=mid+1;
122         else r=mid-1;
123     }
124     if (Query(Root[a],Root[b-lim+2],0,n,L,R)) return true;
125     return false;
126 }
127 
128 int main()
129 {
130     n=read(); q=read();
131     scanf("%s",r);
132     Build_SA(); Build_Height();
133     Build_ST();
134     for (int i=1; i<=n; ++i)
135         Root[i]=Update(Root[i-1],0,n,Rank[i-1]);
136     while (q--)
137     {
138         a=read()-1; b=read()-1; c=read()-1; d=read()-1;
139         int l=1,r=min(b-a+1,d-c+1),ans=0;
140         while (l<=r)
141         {
142             int mid=(l+r)>>1;
143             if (check(mid)) ans=mid, l=mid+1;
144             else r=mid-1;
145         }
146         printf("%d\n",ans);
147     }
148 }
posted @ 2019-02-20 16:02  Refun  阅读(182)  评论(0编辑  收藏  举报