zoukankan      html  css  js  c++  java
  • 字符串(tjoi2016,heoi2016,bzoj4556)(sam(后缀自动机)+线段树合并+倍增+二分答案)

    佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
    一个长为(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
    

    题意:

    中文题面,不解释

    题解:

    首先前缀不好处理,我们把字符串翻转。

    然后发现很难直接求出答案,就采取二分最长后缀并验证。我们只需要验证左区间的后缀是否出现在右区间就行了。

    然后用倍增在(parent)树上找到对应该子串的节点,并求出该节点能覆盖的节点(他子树中的节点),所以我们可以用线段树合并来求解。

    #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
    ",ans);
        }
    } 
    
  • 相关阅读:
    Unity 鼠标控制视角功能和动画播放冲突解决办法
    Unity5.6.4f1 配置WebGL教程
    动态生成圈形+文字的图片
    mysql 常用操作语句
    ideal环境maven自动下载项目依赖配置
    java调用c#dll文件配置
    项目部署到阿里云遇到数据库和访问问题解决记录
    uni-app打印
    JS将时间对象输出为(12小时制和24小时制)的字符串
    基于H5的摄像头视频的采集与传输
  • 原文地址:https://www.cnblogs.com/zhenglier/p/10098921.html
Copyright © 2011-2022 走看看