zoukankan      html  css  js  c++  java
  • 51nod 1600 Simple KMP

    又被机房神犇肉丝哥哥和glory踩爆了

    首先这个答案的输出方式有点套路,当前的答案=上一个答案+每一个后缀的f值=上一个答案+上一次算的每个后缀的f值+当前每个后缀的深度

    这个题意给了个根深度为-1有点诡异,考虑它的现实意义是这个后缀在前面出现了几次,这些后缀的深度和就是前面有多少子串和后缀是能匹配的

    考虑用SAM把fail树搞出来,那么对于加入一个后缀,就是这个叶子到根的路径的点+1,询问也是问当前点到根的和

    拿个LCT维护一下跑路

    离线树剖好像更好写 肉丝早就跑路了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const int _=1e2;
    const int maxn=1e5+_;
    const LL mod=1e9+7;
    
    struct node
    {
        int f,son[2];
        LL s,c;//子树内子串总出现数 子树内子串数 
        LL tot,num;//管理子串数,节点出现次数 
        LL lazy;
    }tr[2*maxn];
    void update(int now)
    {
        int lc=tr[now].son[0],rc=tr[now].son[1];
        tr[now].c=tr[lc].c+tr[rc].c+tr[now].tot;
        tr[now].s=(tr[lc].s+tr[rc].s+tr[now].tot*tr[now].num+(tr[now].c-tr[now].tot)*tr[now].lazy)%mod;
    }
    void pushdown(int now)
    {
        int lc=tr[now].son[0],rc=tr[now].son[1];
        if(lc!=0)tr[lc].num+=tr[now].lazy,tr[lc].lazy+=tr[now].lazy,update(lc);
        if(rc!=0)tr[rc].num+=tr[now].lazy,tr[rc].lazy+=tr[now].lazy,update(rc);
        tr[now].lazy=0;
    }
    void rotate(int x,int w)
    {
        int f=tr[x].f,ff=tr[f].f;
        int R,r;
        
        R=f,r=tr[x].son[w];
        tr[R].son[1-w]=r;
        if(r!=0)tr[r].f=R;
        
        R=ff,r=x;
             if(tr[ff].son[0]==f)tr[R].son[0]=r;
        else if(tr[ff].son[1]==f)tr[R].son[1]=r;
        tr[r].f=R;
        
        R=x,r=f;
        tr[R].son[w]=r;
        tr[r].f=R;
        
        update(f);
        update(x);
    }
    bool isroot(int x,int rt)
    {
        int f=tr[x].f;
        if(f==rt|| tr[f].son[0]!=x&&tr[f].son[1]!=x )return true;
        else return false;
    }
    int tt,tmp[2*maxn];
    void splay(int x,int rt)
    {
        int i=x; tt=0;
        while(!isroot(i,rt))
            tmp[++tt]=i,i=tr[i].f;
        tmp[++tt]=i;
        while(tt>0)
        { 
            if(tr[tmp[tt]].lazy!=0)pushdown(tmp[tt]); 
            tt--;
        }
         
        while(!isroot(x,rt))
        {
            int f=tr[x].f,ff=tr[f].f;
            if(isroot(f,rt))
            {
                if(tr[f].son[0]==x)rotate(x,1);
                else rotate(x,0);
            }
            else
            {
                     if(tr[ff].son[0]==f&&tr[f].son[0]==x)rotate(f,1),rotate(x,1);
                else if(tr[ff].son[1]==f&&tr[f].son[1]==x)rotate(f,0),rotate(x,0);
                else if(tr[ff].son[0]==f&&tr[f].son[1]==x)rotate(x,0),rotate(x,1);
                else if(tr[ff].son[1]==f&&tr[f].son[0]==x)rotate(x,1),rotate(x,0);
            }
        }
    }
    void access(int x)
    {
        int y=0;
        while(x!=0)
        {
            splay(x,0);
            tr[x].son[1]=y;
            if(y!=0)tr[y].f=x;
            update(x);
            y=x;x=tr[y].f;
        }
    }
    void gotop(int x){access(x),splay(x,0);}
    void Link(int x,int y){gotop(x),tr[x].f=y;}
    void Cut(int x)
    {
        gotop(x);
        int lc=tr[x].son[0];
        tr[lc].f=0;tr[x].son[0]=0;
        update(x);
    }
    void add(int x)
    {
        gotop(x);
        tr[x].num++;tr[x].lazy++;
        update(x);
    }
    LL getsum(int x){gotop(x);return tr[x].s;}
    void change(int x,LL tot)
    {
        gotop(x);
        tr[x].tot=tot;
        update(x);
    }
    
    struct SAM
    {
        int w[30],dep,fail;
    }ch[2*maxn];int cnt,last;
    int gettot(int x){return ch[x].dep-ch[ch[x].fail].dep;}
    LL insert(int k,int x)
    {
        int now=++cnt,pre=last; LL ret=0;
        ch[now].dep=k;
        while(pre!=0&&ch[pre].w[x]==0)ch[pre].w[x]=now,pre=ch[pre].fail;
        if(pre==0)
        {
            ch[now].fail=1;
            change(now,gettot(now));
            Link(now,ch[now].fail);
            add(now);
        }
        else
        {
            int nxt=ch[pre].w[x];
            if(ch[nxt].dep==ch[pre].dep+1)
            {
                ch[now].fail=nxt;
                change(now,gettot(now));
                Link(now,ch[now].fail);
                ret=getsum(now);
                add(now);
            }
            else
            {
                int nnxt=++cnt; ch[nnxt]=ch[nxt];
                ch[nnxt].dep=ch[pre].dep+1;
                ch[nxt].fail=nnxt;
                
                change(nxt,gettot(nxt));
                tr[nnxt].num=tr[nxt].num;change(nnxt,gettot(nnxt));
                Cut(nxt);
                Link(nnxt,ch[nnxt].fail);
                Link(nxt,ch[nxt].fail);
    
                //.......先处理nnxt和nxt.......
                
                ch[now].fail=nnxt;
                change(now,gettot(now));
                Link(now,ch[now].fail);
                ret=getsum(now);
                add(now);
                
                //........再搞nnxt和now.......
                
                while(pre!=0&&ch[pre].w[x]==nxt)ch[pre].w[x]=nnxt,pre=ch[pre].fail;
            }
        }
        last=now;
        return ret;
    }
    
    char ss[maxn];
    int main()
    {
    //    freopen("a.in","r",stdin);
    //    freopen("a.out","w",stdout);
        int n;
        scanf("%d%s",&n,ss+1);
        
        LL ans=0,sum=0;
        cnt=last=1;
        for(int i=1;i<=n;i++)
        {
            sum=(sum+insert(i,ss[i]-'a'+1))%mod;
            ans=(ans+sum)%mod;
            printf("%lld
    ",ans);
        }
        
        return 0;
    }
  • 相关阅读:
    参数传递(值传递与引用传递)
    存入redis中的java对象都需要序列化
    windows环境Apache服务器启动失败的原因
    IDEA/Eclipse安装 Alibaba Java Coding Guidelines 插件
    使用freemarker对模板进行渲染
    java使用freemarker作为模板导出Excel表格
    mybatis 中 foreach collection的三种用法
    利用freemarker导出页面格式复杂的excel
    mysql limit和offset用法
    设计模式之二十一:中介者模式(Mediator)
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10575970.html
Copyright © 2011-2022 走看看