[BZOJ4545]DQS的trie(广义后缀自动机+lct)

来源:互联网 发布:php storm10使用教程 编辑:程序博客网 时间:2024/05/16 01:38

题目描述

传送门

题目大意:
先给出一棵trie,然后支持几种操作
若opt=1,则是一组询问,询问当前trie的本质不同的子串数目是多少。
若opt=2,则后面跟两个整数rt,si,表示以点rt为根向下长出一个子树,大小为si。即加入一个子trie
若opt=3,则是一组询问,后面输入一个字符串S,询问字符串S在当前trie中的出现次数。

题解

这题其实是substring和生成魔咒的结合版
opt=1其实就是对于每一个主链上的点,求sigma step(i)-step(pre(i)),每一次extend的时候算一下就行了
opt=3是将S子在自动机上匹配之后求匹配到的点right集合的大小,也就是pa树上子树的大小,用lct维护一下

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 400005int T,n,m,mak,ans3;long long ans1;int mark[N],father[N],last[N];char s[N];int tot,point[N],nxt[N],v[N];char c[N];int root,sz,p,np,q,nq,pre[N],step[N],son[N][5];int f[N],ch[N][2],size[N],delta[N],stack[N];//----------------------------------lct--------------------------------------bool isroot(int x){    return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;}int get(int x){    return ch[f[x]][1]==x;}void pushdown(int x){    if (x&&delta[x])    {        int l=ch[x][0],r=ch[x][1];        if (l) size[l]+=delta[x],delta[l]+=delta[x];        if (r) size[r]+=delta[x],delta[r]+=delta[x];        delta[x]=0;    }}void rotate(int x){    int old=f[x],oldf=f[old],wh=get(x);    if (!isroot(old)) ch[oldf][ch[oldf][1]==old]=x;    f[x]=oldf;    ch[old][wh]=ch[x][wh^1];    if (ch[old][wh]) f[ch[old][wh]]=old;    ch[x][wh^1]=old;    f[old]=x;}void splay(int x){    int top=0;stack[++top]=x;    for (int i=x;!isroot(i);i=f[i]) stack[++top]=f[i];    for (int i=top;i;--i) pushdown(stack[i]);    for (int fa;!isroot(x);rotate(x))        if (!isroot(fa=f[x]))            rotate(get(x)==get(fa)?fa:x);}void access(int x){    int t=0;    for (;x;t=x,x=f[x])    {        splay(x);        ch[x][1]=t;    }}void link(int x,int y){    f[y]=x;    access(x);    splay(x);    size[x]+=size[y];    delta[x]+=size[y];}void cut(int x,int y){    access(y);    splay(y);    size[x]-=size[y];    delta[x]-=size[y];    ch[y][0]=f[x]=0;}//----------------------------------sam--------------------------------------void extend(int p,int x){    np=++sz;    step[np]=step[p]+1;    while (p&&!son[p][x])    {        son[p][x]=np;        p=pre[p];    }    if (!p)    {        pre[np]=root;        link(root,np);    }    else    {        q=son[p][x];        if (step[q]==step[p]+1)        {            pre[np]=q;            link(pre[np],np);        }        else        {            nq=++sz;            step[nq]=step[p]+1;            pre[nq]=pre[q];            link(pre[nq],nq);            memcpy(son[nq],son[q],sizeof(son[q]));            while (p&&son[p][x]==q)            {                son[p][x]=nq;                p=pre[p];            }            cut(pre[q],q);            pre[np]=pre[q]=nq;            link(pre[q],q);            link(pre[np],np);        }    }    ans1+=(long long)step[np]-(long long)step[pre[np]];    access(np);    splay(np);    ++size[np];    ++delta[np];}int sam(){    int len=strlen(s);p=root;    for (int i=0;i<len;++i)    {        int x=s[i]-'a';        p=son[p][x];    }    if (!p) return 0;    access(p);    splay(p);    return size[p];}//----------------------------------trie-------------------------------------void add(int x,int y,int z){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;}void dfs(int x,int fa,int mak){    father[x]=fa;    for (int i=point[x];i;i=nxt[i])        if (v[i]!=fa&&mark[v[i]]==mak)        {            extend(last[x],c[i]);            last[v[i]]=np;            dfs(v[i],x,mak);        }}//----------------------------------main-------------------------------------int main(){    scanf("%d",&T);    scanf("%d",&n);    root=++sz;last[1]=root;    ++mak;    for (int i=1;i<n;++i)    {        int x,y;char z;scanf("%d%d %c",&x,&y,&z);        add(x,y,z-'a'),add(y,x,z-'a');mark[x]=mark[y]=mak;    }    dfs(1,0,mak);    scanf("%d",&m);    while (m--)    {        int opt;scanf("%d",&opt);        if (opt==1) printf("%lld\n",ans1);        else if (opt==2)        {            int ri,si;scanf("%d%d",&ri,&si);            ++mak;            for (int i=1;i<si;++i)            {                int x,y;char z;scanf("%d%d %c",&x,&y,&z);                add(x,y,z-'a'),add(y,x,z-'a');mark[x]=mark[y]=mak;            }            dfs(ri,father[ri],mak);        }        else if (opt==3)        {            scanf("%s",s);            ans3=sam();            printf("%d\n",ans3);        }    }}
0 0
原创粉丝点击