[bzoj4556][Tjoi2016&Heoi2016]字符串
来源:互联网 发布:无线hdmi 知乎 2017 编辑:程序博客网 时间:2024/05/16 18:44
4556: [Tjoi2016&Heoi2016]字符串
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1011 Solved: 397
[Submit][Status][Discuss]
Description
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
O,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公
共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?
Input
输入的第一行有两个正整数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
Output
对于每一次询问,输出答案。
Sample Input
5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4
Sample Output
1
1
2
2
2
HINT
Source
首先我们先后缀数组一下。
然后发现a到b中的子串和c,d做lcp的话,只要管a,b的后缀和c,d的lcp就行了。那暴力肯定T飞了,考虑怎么选比较优秀。
定义lcp(i,j)为i和j的lcp,lcp(i,j)=min(height[rank[i]],…..,height[rank[j]]),那么我们已经知道c的后缀的rank了,那么肯定是离这个rank最近的在[a,b]中的2个rank最优秀。那么我们可以用一个主席树,来取出a,b的区间,然后在主席树上找前驱后继。(谁能教教我怎么在主席树上找前驱和后继啊我报警了,请联系qq591605936,我下面的代码其他对的,找前驱后继复杂度是错的)
然后发现这样会有问题,因为你可能会选到a,b的外面去,所以我们二分一个长度,把这个区间限制一下就行了。
#include<cstdio>#include<algorithm>#include<string>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>using namespace std;int n,m;inline int read(){ char c; bool flag=false; while((c=getchar())>'9'||c<'0') if(c=='-')flag=true; int res=c-'0'; while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0'; return flag?-res:res;}const int N=110000;const int M=1900000;int tot;int sa[N],rank[N],x[N],w[N],hei[N];int lc[M],rc[M],root[N],sum[M];int f[N][19],lg[N];char sr[N];inline void Sa(){ int m=127,u,v; for(int i=1;i<=n;++i) w[x[i]=sr[i]]++; for(int i=1;i<=m;++i) w[i]+=w[i-1]; for(int i=n;i>=1;--i) sa[w[x[i]]--]=i; for(int j=1;j<=n;j*=2) { int cnt=0; for(int i=n-j+1;i<=n;++i) rank[++cnt]=i; for(int i=1;i<=n;++i) if(sa[i]>j) rank[++cnt]=sa[i]-j; for(int i=1;i<=m;++i) w[i]=0; for(int i=1;i<=n;++i) w[x[i]]++; for(int i=1;i<=m;++i) w[i]+=w[i-1]; for(int i=n;i>=1;--i) sa[w[x[rank[i]]]--]=rank[i]; m=0; for(int i=1;i<=n;++i) { u=sa[i];v=sa[i-1]; if(x[u]!=x[v]||x[u+j]!=x[v+j]) ++m; rank[u]=m; } if(m==n) break; for(int i=1;i<=n;++i) x[i]=rank[i]; } int j=0; for(int i=1;i<=n;++i) { u=sa[rank[i]-1]; j=max(j-1,0); while(sr[u+j]==sr[i+j]) ++j; hei[rank[i]]=j; }}inline void insert(int &x,int &y,int l,int r,int val){ int mid=l+r>>1; x=++tot; sum[x]=sum[y]+1; if(l==r) return; lc[x]=lc[y]; rc[x]=rc[y]; if(mid>=val) insert(lc[x],lc[y],l,mid,val); if(mid+1<=val) insert(rc[x],rc[y],mid+1,r,val);} inline int query(int &x,int &y,int l,int r,int L,int R,int shift){ int mid=l+r>>1,res=0; if(L>R) return 0; if(l==r) return l; if(shift==1) { if(sum[lc[x]]-sum[lc[y]]&&mid>=L) res=query(lc[x],lc[y],l,mid,L,R,shift); if(!res&&sum[rc[x]]-sum[rc[y]]&&mid+1<=R) res=query(rc[x],rc[y],mid+1,r,L,R,shift); } else { if(sum[rc[x]]-sum[rc[y]]&&mid+1<=R) res=query(rc[x],rc[y],mid+1,r,L,R,shift); if(!res&&sum[lc[x]]-sum[lc[y]]&&mid>=L) res=query(lc[x],lc[y],l,mid,L,R,shift); } return res;}inline int lcp(int a,int b){ if(a==b) return n-a+1; a=rank[a];b=rank[b]; if(a>b) swap(a,b); int k=lg[b-a]; return min(f[a+1][k],f[b-(1<<k)+1][k]);}inline void rmq(){ lg[1]=0; for(int i=2;i<=n;++i) if(i==(i&-i)) lg[i]=lg[i-1]+1; else lg[i]=lg[i-1]; for(int i=1;i<=n;++i) f[i][0]=hei[i]; for(int j=1;j<=lg[n];++j) for(int i=1;i<=n;++i) if(i+(1<<j)-1>n) break; else f[i][j]=min(f[i+(1<<(j-1))][j-1],f[i][j-1]);}inline bool check(int a,int b,int c,int mid){ int L,R; if(!mid) return 1; L=query(root[b-mid+1],root[a-1],1,n,1,rank[c]-1,0); R=query(root[b-mid+1],root[a-1],1,n,rank[c],n,1); L=sa[L]; R=sa[R]; int LCP=0; if(L) LCP=max(LCP,lcp(L,c)); if(R) LCP=max(LCP,lcp(R,c)); return LCP>=mid;}int main(){// freopen("4556.txt","r",stdin);// freopen("4556out.txt","w",stdout); n=read(); m=read(); scanf("%s",sr+1); Sa(); for(int i=1;i<=n;++i) insert(root[i],root[i-1],1,n,rank[i]); rmq(); int a,b,c,d,l,r; for(int i=1;i<=m;++i) { a=read();b=read(); c=read();d=read(); l=0; r=min(b-a+1,d-c+1); while(l+1<r) { int mid=l+r>>1; if(check(a,b,c,mid)) l=mid; else r=mid; } printf("%d\n",check(a,b,c,r)?r:l); }}
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
- Bzoj4556: [Tjoi2016&Heoi2016]字符串
- BZOJ4556 [Tjoi2016&Heoi2016]字符串
- bzoj4556【TJOI2016&HEOI2016】字符串
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
- [bzoj4556][Tjoi2016&Heoi2016]字符串
- [bzoj4556][TJOI&&HEOI2016]字符串
- [BZOJ4556][Tjoi2016&Heoi2016]字符串(后缀数组+二分+st表+主席树)
- BZOJ4556:[Tjoi2016&Heoi2016]字符串 (后缀自动机+树上倍增+二分答案+线段树合并)
- 4556: [Tjoi2016&Heoi2016]字符串
- [Tjoi2016&Heoi2016]字符串
- JZOJ4614. 【TJOI2016&HEOI2016】字符串
- 【TJOI2016&&HEOI2016】字符串
- 4556: [Tjoi2016&Heoi2016]字符串
- 4556: [Tjoi2016&Heoi2016]字符串
- 【TJOI&HEOI2016】bzoj4556 字符串【解法一】
- 【TJOI&HEOI2016】bzoj4556 字符串【解法二】
- BZOJ 4556 [Tjoi2016&Heoi2016]字符串
- Tcp的四种定时器和三次握手四次挥手协议
- Java性能分析及问题解决(二)jvm致命错误导致进程直接挂掉,错误日志分析及解决
- DFS&&codeforce 598d
- Hibernate教程之七多对多实现基于xml和注解
- LINGO软件入门
- [bzoj4556][Tjoi2016&Heoi2016]字符串
- LightOJ1214
- 第一章:Django开发中url配置及获取参数
- AngularJs 最新验证手机号码,成功测试通过
- [PHP]时间操作
- vim+cscope组合使用配置.vimrc
- Android 监控APP是否在后台运行
- 关于js oop,继承实现的5、6、7、8种方法中的最佳方法
- 回文相关算法