P4094 [HEOI2016/TJOI2016] 字符串
P4094 [HEOI2016/TJOI2016] 字符串
[HEOI2016/TJOI2016] 字符串
题目描述
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为
每个问题均有
对于
Solution:
首先我们注意读题:我们要求
我们考虑二分答案,我们在建 SAM 时记录每个点所对应的节点 pos[i]。这样一来,我们在 parent 树上从
维护 endpos 的方法也不难想到: 线段树合并
Code:
#include<bits/stdc++.h> const int N=4e5+5; const int lg=19; using namespace std; int n,m; struct Segmnet_Tree{ int rt[N],cnt; struct Tree{ int ls,rs,cnt; }t[N*32]; void pushup(int x){t[x].cnt=t[t[x].ls].cnt+t[t[x].rs].cnt;} void insert(int &x,int l,int r,int pos) { t[x= (x ? x : ++cnt)].cnt++; if(l==r)return;int mid=l+r>>1; if(pos<=mid)insert(t[x].ls,l,mid,pos); if(mid<pos)insert(t[x].rs,mid+1,r,pos); } int merge(int x,int y,int l,int r) { if(!x||!y)return x|y; int res=++cnt;t[res].cnt=t[x].cnt+t[y].cnt; if(l==r)return res;int mid=l+r>>1; t[res].ls=merge(t[x].ls,t[y].ls,l,mid); t[res].rs=merge(t[x].rs,t[y].rs,mid+1,r); return res; } int query(int x,int l,int r,int L,int R) { if(!x||R<l||r<L)return 0; if(L<=l&&r<=R)return t[x].cnt; int mid=l+r>>1,res=0; res+=query(t[x].ls,l,mid,L,R); res+=query(t[x].rs,mid+1,r,L,R); return res; } }T; struct SAM{ int ch[N][26],len[N],f[N][lg+5]; int cnt,last; void init(){cnt=last=1;} struct Edge{ int to,nxt; }e[N]; int head[N]; void add(int x,int y){e[++head[0]]={y,head[x]};head[x]=head[0];} void insert(int c) { int p=last,q=++cnt;len[q]=len[last]+1;last=q; for(;p&&!ch[p][c];p=f[p][0])ch[p][c]=q; if(!p){f[q][0]=1;return;}int x=ch[p][c]; if(len[x]==len[p]+1){f[q][0]=x;return;} int y=++cnt;len[y]=len[p]+1;f[y][0]=f[x][0]; for(int i=0;i<26;i++)ch[y][i]=ch[x][i]; f[x][0]=f[q][0]=y; for(;p&&ch[p][c]==x;p=f[p][0])ch[p][c]=y; } void build() { for(int u=2;u<=cnt;u++){add(f[u][0],u);}for(int j=1;j<=lg;j++)for(int u=1;u<=cnt;u++)f[u][j]=f[f[u][j-1]][j-1]; } void dfs(int x) { for(int i=head[x],y=e[i].to;i;i=e[i].nxt,y=e[i].to) { dfs(y);T.rt[x]=T.merge(T.rt[x],T.rt[y],1,n); //cout<<"merge:"<<x<<" "<<y<<"\n"; } } }sam; char s[N]; int id[N]; bool check(int a,int b,int c,int d,int mid) { int now=id[c+mid-1]; for(int j=lg;j>=0;j--){if(sam.f[now][j]&&sam.len[sam.f[now][j]]>=mid){now=sam.f[now][j];}} int tmp=T.query(T.rt[now],1,n,a+mid-1,b); //cout<<"query:"<<id[c+mid-1]<<" "<<now<<": ["<<a+mid-1<<" "<<b<<"]"<<tmp<<"\n"; return tmp>0; } void work() { cin>>n>>m; scanf("%s",s+1); sam.init(); id[0]=1; for(int i=1;i<=n;i++) { sam.insert(s[i]-'a');id[i]=sam.last; T.insert(T.rt[id[i]],1,n,i); } sam.build();sam.dfs(1); for(int i=1,a,b,c,d;i<=m;i++) { scanf("%d%d%d%d",&a,&b,&c,&d); int l=0,r=min(b-a+1,d-c+1),mid=0,ans=0; while(l<=r) { mid=l+r>>1; if(check(a,b,c,d,mid))ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); } } int main() { //freopen("str.in","r",stdin);freopen("str.out","w",stdout); work(); return 0; }