bzoj2555 SubString

Description

懒得写背景了,给你一个字符串init,要求你支持两个操作

(1):在当前字符串的后面插入一个字符串

(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)

你必须在线支持这些操作。
Input

第一行一个数Q表示操作个数

第二行一个字符串表示初始字符串init

接下来Q行,每行2个字符串Type,Str

Type是ADD的话表示在后面插入字符串。

Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。

为了体现在线操作,你需要维护一个变量mask,初始值为0

读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。

HINT:ADD和QUERY操作的字符串都需要解压]

插入字符只需要在SAM上做,询问就是parent树上子树的right集合大小,需要用LCT维护。
但是LCT是不支持对子树的操作的,只需要每次修改一个点的时候,把他到根节点的路径顺便修改。这样就是单链修改,单点查询。注意当且仅当parent树的结构发生改变时需要修改,其他时候只需要下传标记。

#include
#include
#include
using namespace std;
char s[3000010],s1[10];
int fa[3000010],son[3000010][2],trans[3000010][30],val[3000010],
w[3000010],sta[3000010],tag[3000010],
n,q,tot=1,mask,last=1;
int rd(char *s)
{
    int l=0;
    char c=getchar();
    while (c<'A'||c>'Z') c=getchar();
    while (c>='A'&&c<='Z')
    {
        s[++l]=c;
        c=getchar();
    }
    s[l+1]=0;
    return l;
}
int rdi()
{
    int x=0;
    char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    return x;
}
void decode()
{
    int x=mask;
    for (int i=0;i131+i)%n;
        swap(s[i+1],s[x+1]);
    }
}
int is(int u)
{
    return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;
}
void down(int p)
{
    if (tag[p])
    {
        w[p]+=tag[p];
        if (son[p][0]) tag[son[p][0]]+=tag[p];
        if (son[p][1]) tag[son[p][1]]+=tag[p];
        tag[p]=0;
    }
}
void rot(int u,int x)
{
    int v=son[u][x],p=son[v][x^1],q=fa[u];
    if (!is(u)) son[q][son[q][1]==u]=v;
    fa[v]=q;
    son[v][x^1]=u;
    fa[u]=v;
    son[u][x]=p;
    if (p) fa[p]=u;
}
void splay(int u)
{
    int top=0,v,x,y,w;
    for (v=u;;v=fa[v])
    {
        sta[++top]=v;
        if (is(v)) break;
    }
    for (;top;top--) down(sta[top]);
    while (!is(u))
    {
        v=fa[u];
        x=son[v][1]==u;
        if (is(v)) rot(v,x);
        else
        {
            w=fa[v];
            y=son[w][1]==v;
            if (x==y)
            {
                rot(w,y);
                rot(v,x);
            }
            else
            {
                rot(v,x);
                rot(w,y);
            }
        }
    }
}
void access(int u)
{
    int t=u,v=0;
    while (u)
    {
        splay(u);
        son[u][1]=v;
        v=u;
        u=fa[u];
    }
    splay(t);
}
void link(int u,int v)
{
    access(v);
    fa[u]=v;
    down(u);
    tag[v]+=w[u];
}
void cut(int u)
{
    access(u);
    if (son[u][0]) tag[son[u][0]]-=w[u];
    son[u][0]=fa[son[u][0]]=0;
}
int findfa(int u)
{
    access(u);
    int v=son[u][0];
    while (son[v][1]) v=son[v][1];
    return v;
}
void ins(int c)
{
    int p,q,np,nq,tem;
    p=last;
    val[np=++tot]=val[p]+1;
    while (p&&!trans[p][c])
    {
        trans[p][c]=np;
        p=findfa(p);
    }
    if (!p) link(np,1);
    else
    {
        q=trans[p][c];
        if (val[q]==val[p]+1) link(np,q);
        else
        {
            val[nq=++tot]=val[p]+1;
            for (int i=1;i<=26;i++) trans[nq][i]=trans[q][i];
            tem=findfa(q);
            cut(q);
            link(nq,tem);
            link(q,nq);
            link(np,nq);
            while (p&&trans[p][c]==q)
            {
                trans[p][c]=nq;
                p=findfa(p);
            }
        }
    }
    last=np;
    access(np);
    tag[np]++;
}
int qry()
{
    int p=1;
    for (int i=1;i<=n;i++)
        if (!trans[p][s[i]-'A'+1]) return 0;
        else p=trans[p][s[i]-'A'+1];
    access(p);
    return w[p];
}
int main()
{
    /*freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);*/
    int ans;
    q=rdi();
    n=rd(s);
    for (int i=1;i<=n;i++) ins(s[i]-'A'+1);
    while (q--)
    {
        rd(s1);
        n=rd(s);
        decode();
        if (s1[1]=='A')
            for (int i=1;i<=n;i++) ins(s[i]-'A'+1);
        else
        {
            printf("%d\n",ans=qry());
            mask^=ans;
        }
    }
}

你可能感兴趣的:(字符串,数据结构,bzoj)