码迷,mamicode.com
首页 > 其他好文 > 详细

P4094 [HEOI2016/TJOI2016]字符串

时间:2019-12-17 20:32:49      阅读:92      评论:0      收藏:0      [点我收藏+]

标签:sizeof   线段   std   get   字符串   状态   com   inline   --   

题意

考虑二分答案\(mid\),现在我们要判断\(s[c...c+mid-1]\)是否在\(s[a...b]\)出现过。

首先找到\(s[c...c+mid-1]\)所在的状态:
建出\(parent\ tree\),从\(s[1...c+mid-1]\)的节点(这个可以记录)用倍增向上跳到最后一个\(len\geqslant mid\)的节点即可,记这个节点为\(now\)

之后我们要判断\(now\)\(endpos\)中是否含有\([a+mid-1,b]\)中的某个数,我们给每个节点开个权值线段树用来维护该节点\(endpos\)(相当于桶),从\(parent\ tree\)向上合并线段树即可。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=500010;
int n,m,tot,cnt,t;
int id[maxn],root[maxn],head[maxn];
int f[maxn][20];
char s[maxn];
struct edge{int to,nxt;}e[maxn<<1];
struct Seg
{
    #define lc(p) (seg[p].lc)
    #define rc(p) (seg[p].rc)
    #define sum(p) (seg[p].sum)
    int lc,rc,sum;
}seg[maxn*60];
inline int read()
{
    char c=getchar();int res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
inline void add_edge(int u,int v)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;
}
inline void up(int p){sum(p)=sum(lc(p))+sum(rc(p));}
void insert(int &p,int l,int r,int pos)
{
    if(!p)p=++tot;
    sum(p)++;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)insert(lc(p),l,mid,pos);
    else insert(rc(p),mid+1,r,pos);
}
int query(int p,int l,int r,int ql,int qr)
{
    if(l>=ql&&r<=qr)return sum(p);
    int mid=(l+r)>>1,res=0;
    if(ql<=mid)res+=query(lc(p),l,mid,ql,qr);
    if(qr>mid)res+=query(rc(p),mid+1,r,ql,qr);
    return res;
}
int merge(int p,int q,int l,int r)
{
    if(!p||!q)return p+q;   
    int x=++tot,mid=(l+r)>>1;sum(x)=sum(p)+sum(q);
    if(l==r)return x; 
    lc(x)=merge(lc(p),lc(q),l,mid);
    rc(x)=merge(rc(p),rc(q),mid+1,r);
    return x;
}
struct SAM
{
    int tot,last;
    int fa[maxn],len[maxn];
    int ch[maxn][30];
    SAM(){last=tot=1;}
    inline void add(int c)
    {
        int now=++tot;len[now]=len[last]+1;
        int p=last;last=now;
        while(p&&!ch[p][c])ch[p][c]=now,p=fa[p];
        if(!p){fa[now]=1;return;}
        int q=ch[p][c];
        if(len[q]==len[p]+1)fa[now]=q;
        else
        {
            int nowq=++tot;
            len[nowq]=len[p]+1;
            memcpy(ch[nowq],ch[q],sizeof(ch[q]));
            fa[nowq]=fa[q];fa[q]=fa[now]=nowq;
            while(p&&ch[p][c]==q)ch[p][c]=nowq,p=fa[p];
        }
    }
}sam;
void dfs(int x)
{
    for(int i=1;i<=t;i++)f[x][i]=f[f[x][i-1]][i-1];
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        f[y][0]=x;dfs(y);
        root[x]=merge(root[x],root[y],1,n);
    }
}
inline bool check(int mid,int a,int b,int c,int d)
{
    int now=id[c+mid-1];
    for(int i=t;~i;i--)if(f[now][i]&&sam.len[f[now][i]]>=mid)now=f[now][i];
    return query(root[now],1,n,a+mid-1,b)>0;
}
int main()
{
    n=read(),m=read();
    scanf("%s",s+1);
    id[0]=1;
    for(int i=1;i<=n;i++)sam.add(s[i]-'a'),id[i]=sam.last,insert(root[sam.last],1,n,i);
    for(int i=2;i<=sam.tot;i++)add_edge(sam.fa[i],i);
    t=(int)log2(sam.tot)+1;dfs(1);
    while(m--)
    {
        int a=read(),b=read(),c=read(),d=read();
        int l=0,r=min(b-a+1,d-c+1),ans=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(mid,a,b,c,d))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

P4094 [HEOI2016/TJOI2016]字符串

标签:sizeof   线段   std   get   字符串   状态   com   inline   --   

原文地址:https://www.cnblogs.com/nofind/p/12056476.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!