• BZOJ4545 DQS的trie


    Description

    DQS的自家阳台上种着一棵颗粒饱满、颜色纯正的trie。
    DQS的trie非常的奇特,它初始有$n_0$个节点,$n_0-1$条边,每条边上有一个字符。并且,它拥有极强的生长力:某个i时刻,某个节点就会新生长出一颗子树,它拥有$s_i$个节点且节点之间的边上有一个字符,并且新生长出来的子树也是一个树结构。然而因为是新长出来的,根据生活常识可知$s_i$必定不会大于i时刻之前的树的大小。
    DQS定义trie的子串为从根节点($1$号节点)往下走到所有节点所构成的字符串的所有的后缀。DQS身为一个单身doge,常常取出其中一个子串送给妹子,然而他并不希望送给妹子两个相同的子串,所以他非常关心当前trie的本质不同的子串数目。
    DQS有时还会去商店购买子串,若他在商店看上某个子串,他希望得知这个子串是否在自家阳台的trie上已经出现,若出现则出现了多少次。如果出现了,他就可以直接回家取trie上的子串辣!
    然而DQS身为一个蒟蒻,看着自家阳台的trie树一天天在长大,他被如此众多的节点弄得眼花缭乱,于是他找到了IOI2016Au的你。他会告诉你自家trie树的成长历程,他希望你能够对于每一次询问都做出正确回复。

    Solution

    对于询问本质不同的子串数目,可以在构建后缀自动机的时候求出

    对于询问子串出现的次数,相当于询问该子串对应点在parent树上子树和,其中非复制而来的点权值为1

    又因为会有断边操作,所以用LCT维护子树和

    数据:链接:https://pan.baidu.com/s/11daDdDrCPJYgwBWJPIgjog  提取码:bzsv

    #include<iostream>
    #include<cstdio>
    using namespace std;
    namespace LCT
    {
        int tag[200005],tag2[200005],rev[200005],fa[200005],tree[200005][2],v[200005],top,st[200005];
        void pushup(int x)
        {
            tag[x]=tag[tree[x][0]]+tag[tree[x][1]]+tag2[x]+v[x];
        }
        void pushdown(int x)
        {
            if(rev[x])
            {
                if(tree[x][0])
                {
                    rev[tree[x][0]]^=1;
                    swap(tree[tree[x][0]][0],tree[tree[x][0]][1]);
                }
                if(tree[x][1])
                {
                    rev[tree[x][1]]^=1;
                    swap(tree[tree[x][1]][0],tree[tree[x][1]][1]);
                }
                rev[x]=0;
            }
        }
        int getson(int x)
        {
            return tree[fa[x]][1]==x;
        }
        int nroot(int x)
        {
            return tree[fa[x]][0]==x||tree[fa[x]][1]==x;
        }
        void rotate(int x)
        {
            int y=fa[x],z=fa[y],b=getson(x),c=getson(y),a=tree[x][!b];
            if(nroot(y))
            {
                tree[z][c]=x;
            }
            fa[x]=z;
            tree[x][!b]=y;
            fa[y]=x;
            tree[y][b]=a;
            if(a)
            {
                fa[a]=y;
            }
            pushup(y);
            pushup(x);
        }
        void splay(int x)
        {
            int top=0;
            st[++top]=x;
            for(int i=x;nroot(i);i=fa[i])
            {
                st[++top]=fa[i];
            }
            while(top)
            {
                pushdown(st[top--]);
            }
            while(nroot(x))
            {
                int y=fa[x];
                if(nroot(y))
                {
                    getson(x)^getson(y)?rotate(x):rotate(y);
                }
                rotate(x);
            }
        }
        void access(int x)
        {
            for(int y=0;x;x=fa[y=x])
            {
                splay(x);
                tag2[x]+=tag[tree[x][1]]-tag[y];
                tree[x][1]=y;
                pushup(x);
            }
        }
        void makeroot(int x)
        {
            access(x);
            splay(x);
            rev[x]^=1;
            swap(tree[x][0],tree[x][1]);
        }
        void split(int x,int y)
        {
            makeroot(x);
            access(y);
            splay(y);
        }
        void link(int x,int y)
        {
            split(x,y);
            fa[x]=y;
            tag2[y]+=tag[x];
            pushup(y);
        }
        void cut(int x,int y)
        {
            split(x,y);
            tree[y][0]=fa[x]=0;
            pushup(y);
        }
    }
    int id,n0,tot,head[100005],m,rt,s,vst[100005],tim,cnt=1,pos[200005];
    long long ans;
    char str[100005];
    struct Edge
    {
        int to,nxt,w;
    }edge[200005];
    struct SAM
    {
        int ch[5],fa,len;
    }sam[200005];
    inline int read()
    {
        int w=0,f=1;
        char ch=0;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            w=(w<<1)+(w<<3)+ch-'0';
            ch=getchar();
        }
        return w*f;
    }
    int insert(int las,int c)
    {
        int p=las,np=++cnt;
        sam[np].len=sam[p].len+1;
        for(;p&&!sam[p].ch[c];p=sam[p].fa)
        {
            sam[p].ch[c]=np;
        }
        if(!p)
        {
            sam[np].fa=1;
        }
        else
        {
            int q=sam[p].ch[c];
            if(sam[q].len==sam[p].len+1)
            {
                sam[np].fa=q;
            }
            else
            {
                int nq=++cnt;
                sam[nq]=sam[q];
                LCT::link(nq,sam[nq].fa);
                sam[nq].len=sam[p].len+1;
                LCT::cut(q,sam[q].fa);
                sam[q].fa=sam[np].fa=nq;
                LCT::link(q,nq);
                for(;p&&sam[p].ch[c]==q;p=sam[p].fa)
                {
                    sam[p].ch[c]=nq;
                }
            }
        }
        LCT::tag[np]=LCT::v[np]=1;
        LCT::link(np,sam[np].fa);
        ans+=sam[np].len-sam[sam[np].fa].len;
        return np;
    }
    void dfs(int k,int f)
    {
        for(int i=head[k];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v!=f&&vst[v]==tim)
            {
                pos[v]=insert(pos[k],edge[i].w);
                dfs(v,k);
            }
        }
    }
    int main()
    {
        id=read();
        n0=read();
        for(int i=1;i<n0;i++)
        {
            int u=read(),v=read();
            char c;
            cin>>c;
            edge[++tot]=(Edge){v,head[u],c-'a'};
            head[u]=tot;
            edge[++tot]=(Edge){u,head[v],c-'a'};
            head[v]=tot;
        }
        pos[1]=1;
        dfs(1,0);
        m=read();
        for(int i=1;i<=m;i++)
        {
            int opt=read();
            if(opt==1)
            {
                printf("%lld
    ",ans);
            }
            else if(opt==2)
            {
                ++tim;
                rt=read();
                s=read();
                for(int j=1;j<s;j++)
                {
                    int u=read(),v=read();
                    char c;
                    cin>>c;
                    edge[++tot]=(Edge){v,head[u],c-'a'};
                    head[u]=tot;
                    edge[++tot]=(Edge){u,head[v],c-'a'};
                    head[v]=tot;
                    vst[u]=vst[v]=tim;
                }
                dfs(rt,0);
            }
            else
            {
                int p=1;
                scanf("%s",str);
                for(int j=0;str[j];j++)
                {
                    p=sam[p].ch[str[j]-'a'];
                }
                if(p)
                {
                    LCT::makeroot(1);
                    LCT::access(p);
                    LCT::splay(p);
                    printf("%lld
    ",LCT::tag2[p]+LCT::tag[LCT::tree[p][1]]+LCT::v[p]);
                }
                else
                {
                    puts("0");
                }
            }
        }
        return 0;
    }
    DQS的trie
  • 相关阅读:
    移动端日期段选择,不可选过去日期,可传入不可选日期,返回数组
    移动端的silder,未封装,基于zepto的touch模块,有参照修改过touch的bug
    ajax
    简单的cookie读写封装
    自己写的,然后配合zepto+iscroll的上拉加载
    达到
    迷茫
    (转)PropertyGrid相关
    (转)使用NuGet管理项目库
    (转)DDD方面两个开宗明义的文章
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/13542185.html
Copyright © 2020-2023  润新知