bzoj2555-SubString

题目

给出一个初始字符串\(s\),支持两种操作:

  • 在字符串后面添加一个字符串(\(s+=t\)
  • 询问一个字符串在\(s\)中出现了几次

设字符串最终长度为\(n\),询问次数为\(q\),询问字符串总长为\(m\)\(n\le 6\times 10^5, q\le 10^4, m\le 3\times 10^6\)

分析

非常简单的题目。添加字符串用后缀自动机实现,并且用link-cut tree维护后缀树,询问一个字符串出现几次的时候,现在自动机上跑到字符串对应的点\(p\)(如果没有就是无解),再在lct上查询\(p\)的子树中关键点的个数即可。不需要使用TopTree,只需要在每次加点的时候用lct更新链上的点即可。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
const int maxn=6e5+10;
const int maxl=3e6+10;
const int maxc=26;
char s[maxl];
void decode(char s[],int len,int mask) {
    for (int j=0;j<len;++j) {
        mask=(int)((giant)mask*131+j)%len;
        swap(s[mask],s[j]);
    }
}
struct LCT {
    struct node {
        int ch[2],fa,w,sum,size,tag;
        bool rev;
        node ():size(1) {}
    } t[maxn<<1];
    LCT () {t[0].size=0;}
    bool isroot(int x) {
        return !t[x].fa || t[t[x].fa].ch[rson(x)]!=x;
    }
    bool rson(int x) {
        return t[t[x].fa].ch[1]==x;
    }
    void update(int x) {
        t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
        t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].w;
    }
    void down(int x) {
        if (!isroot(x)) down(t[x].fa);
        if (t[x].tag) {
            doit(t[x].ch[0],t[x].tag);
            doit(t[x].ch[1],t[x].tag);
            t[x].tag=0;
        }
        if (t[x].rev) {
            swap(t[x].ch[0],t[x].ch[1]);
            if (t[x].ch[0]) t[t[x].ch[0]].rev^=true;
            if (t[x].ch[1]) t[t[x].ch[1]].rev^=true;
            t[x].rev=false;
        }
    }
    void rotate(int x) {
        int f=t[x].fa,d=rson(x),c=t[x].ch[d^1];
        if (c) t[c].fa=f;
        if (!isroot(f)) t[t[f].fa].ch[rson(f)]=x;
        t[x].fa=t[f].fa,t[f].fa=x,t[x].ch[d^1]=f,t[f].ch[d]=c;
        update(f);
        update(x);
    }
    void splay(int x) {
        down(x);
        while (!isroot(x)) if (isroot(t[x].fa)) rotate(x); else {
            if (rson(x)==rson(t[x].fa)) rotate(x),rotate(x); else 
            rotate(t[x].fa),rotate(x);
        }
    }
    void access(int x) {
        for (int last=0;x;x=t[last=x].fa) {
            splay(x);
            t[x].ch[1]=last;
            update(x);
        }
    }
    void makeroot(int x) {
        access(x);
        splay(x);
        t[x].rev^=true;
    }
    void link(int x,int y) {
        makeroot(x);
        //access(y);
        t[x].fa=y;
    }
    void cut(int x,int y) {
        makeroot(x);
        access(y);
        splay(y);
        t[y].ch[0]=t[x].fa=0;
        update(y);
        update(x);
    }
    int query(int x,int y) {
        makeroot(x);
        access(y);
        splay(y);
        return t[y].sum;
    }
    void doit(int x,int w) {
        t[x].w+=w;
        t[x].sum+=t[x].size*w;
        t[x].tag+=w;
    }
    void add(int x,int y,int w) {
        makeroot(x);
        access(y);
        splay(y);
        doit(y,w);
    }
} lct;
struct SAM {
    int t[maxn<<1][maxc],len[maxn<<1],link[maxn<<1],tot,last;
    SAM ():tot(1),last(1) {}
    void add(int c) {
        int nw=++tot,i;
        len[nw]=len[last]+1;
        for (i=last;i && !t[i][c];i=link[i]) t[i][c]=nw; 
        if (i) {
            int p=t[i][c];
            if (len[p]==len[i]+1) link[nw]=p; else {
                int q=++tot;
                len[q]=len[i]+1;
                memcpy(t[q],t[p],sizeof t[p]);
                for (int j=i;j && t[j][c]==p;j=link[j]) t[j][c]=q;
                int w=lct.query(p,p);
                lct.cut(link[p],p);
                lct.link(link[p],q);
                lct.link(q,p);
                lct.add(q,q,w);
                link[q]=link[p],link[p]=link[nw]=q;
            }
        } else link[nw]=1;
        lct.link(link[nw],nw);
        lct.add(1,nw,1);
        last=nw;
    }
    int run(char s[],int len) {
        int now=1;
        for (int i=0;i<len;++i) now=t[now][s[i]-'A'];
        if (!now) return 0; 
        int ret=lct.query(now,now);
        return ret;
    }
} sam;
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int m,mask=0;
    scanf("%d",&m);
    scanf("%s",s);
    int len=strlen(s);
    for (int i=0;i<len;++i) sam.add(s[i]-'A');
    while (m--) {
        static char ord[10];
        scanf("%s%s",ord,s);
        len=strlen(s);
        decode(s,len,mask);
        if (ord[0]=='A') for (int i=0;i<len;++i) sam.add(s[i]-'A'); else {
            int ans=sam.run(s,len);
            mask^=ans;
            printf("%d\n",ans);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/6724640.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值