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 }
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!