【TJOI&HEOI2016】bzoj4556 字符串【解法二】
来源:互联网 发布:wap网投源码 编辑:程序博客网 时间:2024/05/16 14:13
解法一【后缀数组+二分答案+主席树】见【这里】。
直接在后缀自动机上处理LCP不好做,可以做反串的LCS(uffix)。还是先二分答案,在SAM上定位这一段子串对应的节点,具体做法是先预处理出每个前缀对应的节点,然后在fail树上倍增。找到这个节点以后,只需要检查这个节点的right集合里有没有符合要求的位置。这里需要用线段树合并来维护每个节点的right集合。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=200010,maxt=4000010;char s[maxn];int trans[maxn][30],val[maxn],fail[maxn],root[maxt],lson[maxt],rson[maxt],sum[maxt],pos[maxn],fa[maxn][25],cnt[maxn],que[maxn],n,q,tot=1,num;int add(int L,int R,int x){ int u=++num; sum[u]=1; if (L==R) return u; int mid=L+R>>1; if (x<=mid) lson[u]=add(L,mid,x); else rson[u]=add(mid+1,R,x); return u;}int merge(int u,int v,int L,int R){ if (u*v==0) return u+v; int x=++num; if (L==R) { sum[x]=sum[u]+sum[v]; return x; } int mid=L+R>>1; lson[x]=merge(lson[u],lson[v],L,mid); rson[x]=merge(rson[u],rson[v],mid+1,R); sum[x]=sum[lson[x]]+sum[rson[x]]; return x;}int find(int u,int L,int R,int l,int r){ if (!sum[u]) return 0; if (L==R) return 1; int mid=L+R>>1; if (l<=mid&&find(lson[u],L,mid,l,r)) return 1; if (r>mid&&find(rson[u],mid+1,R,l,r)) return 1; return 0; }int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int u,nu,v,nv,last=1,x,lim,a,b,c,d,l,r,mid; scanf("%d%d",&n,&q); scanf("%s",s+1); for (int i=1;i<n-i+1;i++) swap(s[i],s[n-i+1]); for (int i=1;i<=n;i++) { x=s[i]-'a'+1; val[nu=++tot]=val[u=last]+1; last=nu; while (u&&!trans[u][x]) { trans[u][x]=nu; u=fail[u]; } if (!u) fail[nu]=1; else { v=trans[u][x]; if (val[v]==val[u]+1) fail[nu]=v; else { val[nv=++tot]=val[u]+1; fail[nv]=fail[v]; fail[v]=fail[nu]=nv; for (int j=1;j<=26;j++) trans[nv][j]=trans[v][j]; while (u&&trans[u][x]==v) { trans[u][x]=nv; u=fail[u]; } } } } u=1; for (int i=1;i<=n;i++) { u=trans[u][s[i]-'a'+1]; pos[i]=u; root[u]=add(1,n,i); } for (int i=1;i<=tot;i++) fa[i][0]=fail[i]; for (int k=1;(1<<k)<=tot;k++) for (int i=1;i<=tot;i++) fa[i][k]=fa[fa[i][k-1]][k-1]; for (int i=1;i<=tot;i++) cnt[val[i]]++; for (int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; for (int i=1;i<=tot;i++) que[cnt[val[i]]--]=i; for (int i=tot;i;i--) root[fail[que[i]]]=merge(root[fail[que[i]]],root[que[i]],1,n); while (q--) { scanf("%d%d%d%d",&a,&b,&c,&d); a=n-a+1; b=n-b+1; c=n-c+1; d=n-d+1; swap(a,b); swap(c,d); l=0; r=min(b-a+1,d-c+1); while (l<r) { mid=(l+r+1)/2; u=pos[d]; for (int k=1;;k++) { lim=k; if (val[fa[u][k]]<mid) break; } for (int k=lim;k>=0;k--) if (val[fa[u][k]]>=mid) u=fa[u][k]; if (find(root[u],1,n,a+mid-1,b)) l=mid; else r=mid-1; } printf("%d\n",l); }}
阅读全文
0 0
- 【TJOI&HEOI2016】bzoj4556 字符串【解法二】
- 【TJOI&HEOI2016】bzoj4556 字符串【解法一】
- [bzoj4556][TJOI&&HEOI2016]字符串
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
- Bzoj4556: [Tjoi2016&Heoi2016]字符串
- BZOJ4556 [Tjoi2016&Heoi2016]字符串
- bzoj4556【TJOI2016&HEOI2016】字符串
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
- [bzoj4556][Tjoi2016&Heoi2016]字符串
- [TJOI&HEOI2016]str/[JZOJ4614]字符串
- Loj2059. 「TJOI / HEOI2016」字符串
- [bzoj4551][TJOI&HEOI2016]树
- [bzoj4552][TJOI&HEOI2016]排序
- [bzoj4553][TJOI&HEOI2016]序列
- [bzoj4552][TJOI&&HEOI2016]排序
- [TJOI&HEOI2016]排序
- [bzoj4555][TJOI&HEOI2016]求和
- 【bzoj4555】[TJOI&HEOI2016]求和
- Shell脚本——make命令和Makefile文件
- FileReader -- 图片预览问题
- 数据结构之链表
- 从把三千行代码重构成15行代码谈起
- 从插上网线到web页面请求,究竟发生了哪些过程?(计算机网络篇)
- 【TJOI&HEOI2016】bzoj4556 字符串【解法二】
- Error:Configuration with name 'default' not found.
- 前端应该知道的一些东东啦~
- PropertyGrid控件由浅入深(一):文章大纲
- pythonGUI编程(Tkinter)(1)
- 完善一个iOS程序的界面功能:使用StackView以及其他UI元素
- libsvm 的使用
- javascript创建元素和删除元素
- Selenium无法定位元素