佳媛姐姐過生日的時候,她的小夥伴從某東上買了一個生日禮物。生日禮物放在一個神奇的箱子中。箱子外邊寫了 一個長爲$n$的字符串$s$,和$m$個問題。佳媛姐姐必須正確回答這$m$個問題,才能打開箱子拿到禮物,升職加薪,出任CE O,嫁給高富帥,走上人生巔峯。每一個問題均有$a,b,c,d$四個參數,問你子串$s[a..b]$的全部子串和$s[c..d]$的最長公 共前綴的長度的最大值是多少?佳媛姐姐並不擅長作這樣的問題,因此她向你求助,你該如何幫助她呢?c++
輸入的第一行有兩個正整數$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$spa
對於每一次詢問,輸出答案。code
5 5 aaaaa 1 1 1 5 1 5 1 1 2 3 2 3 2 4 2 3 2 3 2 4
1 1 2 2 2
中文題面,不解釋ci
首先前綴很差處理,咱們把字符串翻轉。字符串
而後發現很難直接求出答案,就採起二分最長後綴並驗證。咱們只須要驗證左區間的後綴是否出如今右區間就好了。it
而後用倍增在$parent$樹上找到對應該子串的節點,並求出該節點能覆蓋的節點(他子樹中的節點),因此咱們能夠用線段樹合併來求解。ast
#include<bits/stdc++.h> #define mid (l+(r-l)/2) using namespace std; const int N=200010; int lson[N*30],rson[N*30],sum[N*30]; int n,m,head[N],nxt[N],bian[N],p,q,np,nq,mp[N],pos[N],cnt,last; int root[N],ch[N][27],fa[N],l[N],tot,sz,f[N][19],dep[N]; char s[N]; void ins(int x) { int c=s[x]-'a'+1; p=last; np=++cnt; last=np; mp[np]=x; pos[x]=np; l[np]=l[p]+1; for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; if (!p) fa[np]=1; else { q=ch[p][c]; if (l[p]+1==l[q]) fa[np]=q; else { nq=++cnt; l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; } } } void add(int x,int y){ tot++,bian[tot]=y,nxt[tot]=head[x],head[x]=tot; } int updata(int pre,int l,int r,int x){ int rt=++sz; sum[rt]=sum[pre]+1; if (l==r) return rt; lson[rt]=lson[pre]; rson[rt]=rson[pre]; if (x<=mid) lson[rt]=updata(lson[pre],l,mid,x); else rson[rt]=updata(rson[pre],mid+1,r,x); return rt; } void pushup(int x){ int l=lson[x],r=rson[x]; sum[x]=sum[l]+sum[r]; } int merge(int x,int y){ if(!x||!y)return x+y; int rt=++sz; lson[rt]=merge(lson[x],lson[y]); rson[rt]=merge(rson[x],rson[y]); pushup(rt); return rt; } void dfs(int x){ for (int i=1;i<=17;i++){ if (dep[x]-(1<<i)<0) break; f[x][i]=f[f[x][i-1]][i-1]; } for (int i=head[x];i;i=nxt[i]){ f[bian[i]][0]=x,dep[bian[i]]=dep[x]+1; dfs(bian[i]); root[x]=merge(root[x],root[bian[i]]); } } int query(int rt,int l,int r,int x,int y){ if(x<=l&&r<=y)return sum[rt]; int ans=0; if(x<=mid)ans+=query(lson[rt],l,mid,x,y); if(y>mid)ans+=query(rson[rt],mid+1,r,x,y); return ans; } bool check(int k,int left,int right,int x){ if(k==0)return 1; for(int rt=17;rt>=0;rt--) if(l[f[x][rt]]>=k)x=f[x][rt]; return query(root[x],1,n,left,right); } int main(){ cin>>n>>m; cin>>s+1;reverse(s+1,s+n+1); last=++cnt; for(int i=1;i<=n;++i)ins(i); for(int i=1;i<=cnt;++i)add(fa[i],i); for(int i=1;i<=cnt;++i) if(mp[i])root[i]=updata(root[i],1,n,mp[i]); dep[1]=1; dfs(1); for (int i=1;i<=m;++i){ int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); swap(a,b); swap(c,d); a=n-a+1; b=n-b+1; c=n-c+1; d=n-d+1; int l=0,r=min(d-c+1,b-a+1),ans=0; while (l<=r){ if (check(mid,a+mid-1,b,pos[d])) ans=max(ans,mid),l=mid+1; else r=mid-1; } printf("%d\n",ans); } }