BZOJ4556 [Tjoi2016&Heoi2016]字符串
2016-06-14 10:10
405 查看
恩,我们进行一些瞎YY,首先询问s[a~b]的所有子串与S[c~d]的最长LCP其实相当于询问s[a~b]的所有后缀与s[c~d]的最长LCP与这个子串的长度还有c~d的长度取min
进一步转化设suf[i]表示S的从第i个字符开始的后缀,则其实相当于询问这个
![](http://img.blog.csdn.net/20160614102230643)
可以把d-c+1提到外面,就变成
![](http://img.blog.csdn.net/20160614102703988)
这样只需要考虑左面的,考虑若答案为l(l<=d-c+1),则作为答案的后缀不可能取在i>b-l+1的位置,而在a<=i<=b-l+1的范围内,只要LCP(suf[i],suf[c])>=l,那么s[i~b]就是一个与s[c~d]有长度为l的LCP的子串
这样我们可以在<=d-c+1的范围内二分答案,每次只要判断a<=i<=b-mid+1的范围内是否存在LCP(suf[i],suf[c])>=mid即可,这个判断可以先建一颗后缀树,在后缀树上倍增找到suf[c]的最浅的长度>=mid的祖先,然后判断这个祖先的子树内是否有a<=i<=b-mid+1的后缀即可,这个可以用主席树
复杂度 O(m log^2 n)
进一步转化设suf[i]表示S的从第i个字符开始的后缀,则其实相当于询问这个
可以把d-c+1提到外面,就变成
这样只需要考虑左面的,考虑若答案为l(l<=d-c+1),则作为答案的后缀不可能取在i>b-l+1的位置,而在a<=i<=b-l+1的范围内,只要LCP(suf[i],suf[c])>=l,那么s[i~b]就是一个与s[c~d]有长度为l的LCP的子串
这样我们可以在<=d-c+1的范围内二分答案,每次只要判断a<=i<=b-mid+1的范围内是否存在LCP(suf[i],suf[c])>=mid即可,这个判断可以先建一颗后缀树,在后缀树上倍增找到suf[c]的最浅的长度>=mid的祖先,然后判断这个祖先的子树内是否有a<=i<=b-mid+1的后缀即可,这个可以用主席树
复杂度 O(m log^2 n)
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<iomanip> #include<vector> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> using namespace std; #define MAXN 200010 #define MAXM 4000010 #define ll long long #define INF 1000000000 #define MOD 1000000007 #define eps 1e-8 struct vec{ int to; int fro; }; int fa[MAXN],son[MAXN][26],mx[MAXN]; int rt,lst,tot; int n,m; char s[MAXN]; int Son[MAXM][2],Siz[MAXM]; int Tot; int Rt[MAXN]; vec mp[MAXN]; int tai[MAXN],cnt; int dfn[MAXN],ndf[MAXN],siz[MAXN],tim; int Fa[MAXN][20]; int dep[MAXN]; int P[MAXN]; vector<int>tp[MAXN]; inline void be(int x,int y){ mp[++cnt].to=y; mp[cnt].fro=tai[x]; tai[x]=cnt; } void ins(int x){ int np=++tot,p=lst; mx[np]=mx[p]+1; while(p&&!son[p][x]){ son[p][x]=np; p=fa[p]; } if(!p){ fa[np]=rt; }else{ int q=son[p][x]; if(mx[q]==mx[p]+1){ fa[np]=q; }else{ int nq=++tot; mx[nq]=mx[p]+1; memcpy(son[nq],son[q],sizeof(son[q])); fa[nq]=fa[q]; fa[np]=fa[q]=nq; while(p&&son[p][x]==q){ son[p][x]=nq; p=fa[p]; } } } lst=np; } void dfs(int x){ int i,j,t,y; dfn[x]=++tim; ndf[tim]=x; siz[x]=1; dep[x]=dep[Fa[x][1]]+1; for(i=tai[x];i;i=mp[i].fro){ y=mp[i].to; for(t=x,j=1;t;j++){ Fa[y][j]=t; t=Fa[t][j]; } dfs(y); siz[x]+=siz[y]; } } void change(int &x,int xx,int l,int r,int p){ x=++Tot; memcpy(Son[x],Son[xx],sizeof(Son[x])); Siz[x]=Siz[xx]+1; if(l==r){ return ; } int mid=l+r>>1; if(p<=mid){ change(Son[x][0],Son[xx][0],l,mid,p); }else{ change(Son[x][1],Son[xx][1],mid+1,r,p); } } int anc(int x,int y){ int i; for(i=19;i;i--){ if(mx[Fa[x][i]]>=y){ x=Fa[x][i]; } } return x; } int ask(int x,int xx,int y,int z,int l,int r){ if(y==l&&z==r){ return Siz[xx]-Siz[x]; } int mid=y+z>>1; if(r<=mid){ return ask(Son[x][0],Son[xx][0],y,mid,l,r); }else if(l>mid){ return ask(Son[x][1],Son[xx][1],mid+1,z,l,r); }else{ return ask(Son[x][0],Son[xx][0],y,mid,l,mid)+ask(Son[x][1],Son[xx][1],mid+1,z,mid+1,r); } } bool OK(int x,int y,int z){ return ask(Rt[dfn[x]-1],Rt[dfn[x]+siz[x]-1],1,n,y,z); } int main(){ lst=rt=tot=1; int i,j,x,y,xx,yy; scanf("%d%d",&n,&m); scanf("%s",s+1); int p=rt; for(i=n;i;i--){ ins(s[i]-'a'); p=son[p][s[i]-'a']; P[i]=p; tp[P[i]].push_back(i); } for(i=2;i<=tot;i++){ be(fa[i],i); } dfs(1); for(i=1;i<=tim;i++){ Rt[i]=Rt[i-1]; for(j=0;j<tp[ndf[i]].size();j++){ change(Rt[i],Rt[i],1,n,tp[ndf[i]][j]); } } while(m--){ scanf("%d%d%d%d",&x,&y,&xx,&yy); int l=1,r=min(yy-xx+1,y-x+1); int ans=0; while(l<=r){ int mid=l+r>>1; if(OK(anc(P[xx],mid),x,y-mid+1)){ ans=mid; l=mid+1; }else{ r=mid-1; } } printf("%d\n",ans); } return 0; } /* 8 1 ababcabc 1 3 6 8 */
相关文章推荐
- MyEclipse服务器远程调试
- man 命令查看 格式解读
- PL/SQL基础篇
- 基于gulp合并压缩Seajs模块的方式说明
- 数据库和数据仓库的区别
- UITextField添加Block
- 有赞分层自动化测试实践
- js算法: inserting sort 插入排序
- json-lib 的maven dependency
- Base64
- JsonConverte扩展
- C++中析构函数的作用,
- dashboard session backend由 signed cookie切换成database
- DES加密 个人使用之后的
- Xamarin Android SDK无法更新的解决办法
- 管理Activity
- java
- linux命令--wget
- HTTPS那些事 用java实现HTTPS工作原理
- 二进制幂--求解a^n问题