[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);    }}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 佰仟乐购额度没有了怎么办 交易密码忘记了怎么办? 电脑打开没网怎么办 网络配适器无法运行怎么办 电脑dns没有响应怎么办 win7系统没有网上邻居怎么办 win10网络重置了怎么办 win7桌面没有网上邻居怎么办 win7电脑没有网上邻居怎么办 无线网连接受限怎么办 win7账户被锁定怎么办 贷款sdk授权失败怎么办 京东保价发票怎么办 淘宝购物出现质量问题怎么办 淘宝购物降价了怎么办 淘宝购物物流慢怎么办 在淘宝购物退货怎么办 淘宝购物未付款怎么办 淘宝购物余额不足怎么办 淘宝购物漏发货怎么办 京东618无货怎么办 iis默认文档无效怎么办? 购物卡没有磁性怎么办 墙面贴纸没有贴怎么办 车显示电池符号怎么办 遇上北京购物团怎么办 钱柜老是钱不见怎么办 写真顾客退单怎么办 电视不支持投屏怎么办 qq转错账的钱怎么办 qq关注不了别人怎么办 换货忘记要单号怎么办 快递提前签收了怎么办 签收了不明快递怎么办 京东签收了怎么办 快递被签收了怎么办 香港旅游团强制购物怎么办 爱奇艺京东会员领不了怎么办 买手机买到翻新机怎么办 买了翻新机怎么办 苹果四激活出错怎么办