BZOJ 4556 [Tjoi2016&Heoi2016]字符串

题解:

神题

我们二分一个答案k

在(a,b-k+1)中找一个与c的最长公公前缀

从c在rank数组中的位置向两边扩展直到min<k,边界(l,r)

然后在(l,r)中找到有没有(a,b-k+1)中的元素,主席树实现,差分

一但找到立刻return;

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 const int maxn=200009;
  8 
  9 int n,TT;
 10 char s[maxn];
 11 
 12 int t1[maxn],t2[maxn];
 13 int c[maxn],sa[maxn];
 14 void BuildSA(int m){
 15     int *x=t1,*y=t2;
 16     
 17     for(int i=1;i<=m;++i)c[i]=0;
 18     for(int i=1;i<=n;++i)c[x[i]=s[i]]++;
 19     for(int i=2;i<=m;++i)c[i]+=c[i-1];
 20     for(int i=n;i>=1;--i)sa[c[x[i]]--]=x[i];
 21     
 22     for(int k=1;k<n;k<<=1){
 23         int p=0;
 24         for(int i=n-k+1;i<=n;++i)y[++p]=i;
 25         for(int i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k;
 26         
 27         for(int i=1;i<=m;++i)c[i]=0;
 28         for(int i=1;i<=n;++i)c[x[y[i]]]++;
 29         for(int i=2;i<=m;++i)c[i]+=c[i-1];
 30         for(int i=n;i>=1;--i)sa[c[x[y[i]]]--]=y[i];
 31         
 32         swap(x,y);
 33         x[sa[1]]=p=1;
 34         for(int i=2;i<=n;++i){
 35             if((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+k]==y[sa[i-1]+k]))p:++p;
 36         }
 37         if(p>=n)break;
 38         m=p;
 39     }
 40 }
 41 
 42 int rk[maxn],ht[maxn];
 43 void GetHeight(){
 44     int k=0;
 45     for(int i=1;i<=n;++i)rk[sa[i]]=i;
 46     
 47     for(int i=1;i<=n;++i){
 48         if(k)--k;
 49         int j=sa[rk[i]-1];
 50         while(s[i+k]==s[j+k])++k;
 51         ht[rk[i]]=k;
 52     }
 53 }
 54 
 55 int PTsiz=0;
 56 int root[maxn];
 57 struct SegmentTree{
 58     int l,r,d,ls,rs;
 59 }tree[maxn*30];
 60 void BuildTree(int &now,int l,int r){
 61     now=++PTsiz;
 62     tree[now].l=l;tree[now].r=r;tree[now].d=0;
 63     if(l==r)return;
 64     int mid=(l+r)>>1;
 65     BuildTree(tree[now].ls,l,mid);
 66     BuildTree(tree[now].rs,mid+1,r);
 67 }
 68 void Updatapoint(int &now,int pre,int pla){
 69     now=++PTsiz;
 70     tree[now]=tree[pre];
 71     tree[now].d++;
 72     if(tree[now].l==tree[now].r)return;
 73     int mid=(tree[now].l+tree[now].r)>>1;
 74     if(pla<=mid)Updatapoint(tree[now].ls,tree[pre].ls,pla);
 75     else Updatapoint(tree[now].rs,tree[pre].rs,pla);
 76 }
 77 int Querysum(int now,int pre,int ll,int rr){
 78     if(tree[now].l>=ll&&tree[now].r<=rr){
 79         int d=tree[now].d-tree[pre].d;
 80         if(d)return 1;
 81         else return 0;
 82     }
 83     int mid=(tree[now].l+tree[now].r)>>1;
 84     int ret=0;
 85     if(ll<=mid)ret=Querysum(tree[now].ls,tree[pre].ls,ll,rr);
 86     if(rr>mid)ret|=Querysum(tree[now].rs,tree[pre].rs,ll,rr);
 87     return ret;
 88 }
 89 
 90 int f[maxn][20];
 91 int ds[maxn];
 92 void STinit(){
 93     for(int i=1;i<=n;++i)f[i][0]=ht[i];
 94     for(int j=1;j<=19;++j){
 95         for(int i=1;i+(1<<j)-1<=n;++i){
 96             f[i][j]=min(f[i][j-1],f[i+(1<<j)][j-1]);
 97         }
 98     }
 99 }
100 int Querymin(int l,int r){
101     int k=ds[r-l+1];
102     return min(f[l][k],f[r-(1<<k)+1][k]);
103 }
104 
105 int l_bound(int l,int r,int c,int len){
106     int mid,ans=c;
107     while(l<=r){
108         mid=(l+r)>>1;
109         if(Querymin(mid+1,c)>=len){
110             ans=mid;r=mid-1;
111         }else{
112             l=mid+1;
113         }
114     }
115     return ans;
116 }
117 int r_bound(int l,int r,int c,int len){
118     int mid,ans=c;
119     while(l<=r){
120         mid=(l+r)>>1;
121         if(Querymin(c+1,mid)>=len){
122             ans=mid;l=mid+1;
123         }else{
124             r=mid-1;
125         }
126     }
127     return ans;
128 }
129 
130 int Getans(int ll,int rr,int c,int d){
131     int pla=rk[c];
132     int l=0,r=min(rr-ll+1,d-c+1),mid,ans=0;
133     while(l<=r){
134         mid=(l+r)>>1;
135         int tl=l_bound(1,pla-1,c,mid);
136         int tr=r_bound(pla+1,n,c,mid);
137         if(Querysum(root[tr],root[tl-1],ll,rr-mid+1)){
138             ans=mid;
139             l=mid+1;
140         }else{
141             r=mid-1;
142         }
143     }
144     return ans;
145 }
146 
147         
148 int main(){
149     scanf("%d%d",&n,&TT);
150     scanf("%s",s+1);
151     BuildSA(200);
152     GetHeight();
153     BuildTree(root[0],1,n);
154     for(int i=1;i<=n;++i)Updatapoint(root[i],root[i-1],sa[i]);
155     for(int i=1;i<=n;++i)ds[i]=log2(i+0.5);
156     STinit();
157     
158     while(TT--){
159         int a,b,c,d;
160         scanf("%d%d%d%d",&a,&b,&c,&d);
161         printf("%d\n",(Getans(a,b,c,d)));
162     }
163     return 0;
164 }

 

posted @ 2018-03-21 21:59  ws_zzy  阅读(156)  评论(0编辑  收藏  举报