zoukankan      html  css  js  c++  java
  • [HNOI2019]JOJO


    不错的好题

    有一个比较弱化的问题:

    [题集]串

    已知小串的子串问题,例题2


    本题:

    首先单纯快速跳kmp就要用到AC自动机的fail了(单串AC自动机)

    所谓回撤,就是一个可持久化,

    建出时间树,直接dfs,回来的时候撤销这一路的操作。

    问题就是往S后插入x个c,考虑新加入的fail之和

    我们把(x,c)尽量看成一个整体 (请感性理解这句话23333)

    不妨称一个操作(边)为(x,c)

    这里一个重要条件:每次的x个c一定是极长的,也就是当前结尾不是c字符

    那么我们的fail[u]只用保留一个节点,而不是“边”,一定是一个(x,c)的结束位置

    支持找失配点,我们要维护fail

    手玩发现,最后一个(x,c)其实不太好维护

    那么考虑fail树链上的前面部分的答案。

    再处理新加入(x,c)的每个插入[1,x]个字符单独产生的贡献

    (后面所有的处理都是基于这个的)

    每个点2*26棵主席树,

    1.支持查询答案,我们用一组26棵主席树rt1[u][c],叶子节点x权值就是假如插入了(x,c),整个u在fail树路径上,有(x,c)出边的、匹配的最长长度

     

     2.第二棵主席树就是fail的出边

    而根据“那么我们的fail[u]只用保留一个节点,而不是“边”,一定是一个(x,c)的结束位置”

    所以,第二棵主席树rt2[u][c]的节点x权值是:u的fail树祖先上,第一个恰好有(x,c)出边,这个(x,c)出边指向的儿子节点

    3.为了统计答案的时候 统计单独产生的贡献,我们还需要维护mx[u][c]表示,u节点从fail树祖先过来,的c字符出边最长的x是多少。

    (好绕啊。。。。)

    对于u节点后面插入v节点,边是(x,c)

    要做如下事情:

    查询新增的答案

    1.查询rt1[u][c]的(1~x)的和

    2.令t=min(x,mx[u][c]),ans+=t*(t+1)/2,这个是(x,c)单独贡献的

    3.当mx[u][c]更小的时候,一个问题:

    这个时候意味着红色这个全是x组成的后缀并没有单独做出贡献

    但是假设当前开始也是c这个字符,长度为sx,那么每一个都可以和这个红色部分结尾的前缀进行一次kmp的贡献

    也就是,ans+=(x-t)*sx(因为这个时候,x一定比sx大)

    更新?

    关于u的

    1.mx[u][c]=max(mx[u][c],x)

    2.rt1[u][c].upda(1,x,len[u])(len表示当前串到u节点的长度)

    3.rt2[u][c].upda(x,v)如果之后某个点的fail是u,并且有一个(x,c)的出边,那么v可以直接作为该出边节点的fail

    关于v的:

    1.fail[v]的维护?令fa=rt2[u][c].x,

    如果fa不是0,那么fail[v]=fa

    如果fa是0,还是有这种可能:

    假设开始的字符确实是x,并且sx<=x

    那么,可以直接把这第一个出点firstcur,作为fail[v]

    否则,fail[v]=0

    2.rt1,rt2,mx都从fail[v]继承过来 

    然后就没了

    (是不是很麻烦)

    其实都是围绕

    那么考虑fail树链上的前面部分的答案。

    再处理新加入(x,c)的每个插入[1,x]个字符单独产生的贡献

    展开的,对于维护和统计答案还需要维护别的东西而已

    出错点:

    1.len是+x的

    2.输出回车换行。。

    3.还原时候,u=0,要直接赋值为0

    4.多pushup了一次(没有pushdown的时候不能pushup!)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=100000+5;
    const int mod=998244353;
    const int lim=10000;
    #define mid ((l+r)>>1)
    int n;
    int ans[N];
    int to[N];
    struct edge{
        int nxt,to;
        int x,c;
    }e[N];
    int hd[N],cnt;
    void add(int u,int v,int ct,int c){
        e[++cnt].nxt=hd[u];
        e[cnt].to=v;
        e[cnt].c=c;
        e[cnt].x=ct;
        hd[u]=cnt;
    }
    struct node{
        int ls,rs;
        int nxt,val;
        int tag;
        node(){
            ls=0;rs=0;nxt=0;val=0;tag=-1;
        }
    }t[N*80];
    int tot;
    int rt[N][26];
    int sx,sc,fc;
    int mx[N][26];
    int fail[N];
    int ad(int x,int y){
        return x+y>=mod?x+y-mod:x+y;
    }
    void pushup(int x){
        t[x].val=ad(t[t[x].ls].val,t[t[x].rs].val);
    }
    int cpy(int cur){
        ++tot;t[tot]=t[cur];return tot;
    }
    void tag(int &x,int l,int r,int c){
    //    cout<<" tag "<<c<<endl;
        x=cpy(x);
        t[x].tag=c;
        t[x].val=(ll)c*(r-l+1)%mod;
    }
    void pushdown(int x,int l,int r){
        if((!x)||(t[x].tag==-1)) return;
        tag(t[x].ls,l,mid,t[x].tag);
        tag(t[x].rs,mid+1,r,t[x].tag);
        t[x].tag=-1;
    }
    void chan(int &x,int y,int l,int r,int L,int R,int c){
        
        if(!x){
            x=cpy(y);
        }
    //    cout<<" chan "<<" x "<<x<<" : "<<l<<" "<<r<<" L "<<L<<" R "<<R<<" c "<<c<<" val "<<t[x].val<<endl;
        if(L<=l&&r<=R){
            t[x].tag=c;
            t[x].val=(ll)c*(r-l+1)%mod;
            return;
        }
        pushdown(x,l,r);
        if(L<=mid){
            t[x].ls=cpy(t[x].ls);chan(t[x].ls,t[y].ls,l,mid,L,R,c);
        }
        if(mid<R){
            t[x].rs=cpy(t[x].rs);chan(t[x].rs,t[y].rs,mid+1,r,L,R,c);
        }
        pushup(x);
    }
    void upda(int &x,int y,int l,int r,int p,int to){
        if(!x){
            x=cpy(y);
        }
        if(l==r){
            t[x].nxt=to;return;
        }
        // pushdown(x,l,r);//dele ?
        //warning!! no pushdown
        if(p<=mid){
            t[x].ls=cpy(t[x].ls);upda(t[x].ls,t[y].ls,l,mid,p,to);
        }else{
            t[x].rs=cpy(t[x].rs);upda(t[x].rs,t[y].rs,mid+1,r,p,to);
        }
    //    pushup(x);
    }
    int query(int x,int l,int r,int L,int R){
    //    cout<<" query "<<" x "<<x<<" : "<<l<<" "<<r<<" L "<<L<<" R "<<R<<" val "<<t[x].val<<endl;
        if(L<=l&&r<=R){
            return t[x].val;
        }
        pushdown(x,l,r);
        if(R<=mid) return query(t[x].ls,l,mid,L,R);
        if(mid<L) return query(t[x].rs,mid+1,r,L,R);
        return ad(query(t[x].ls,l,mid,L,R),query(t[x].rs,mid+1,r,L,R));
    }
    int fin(int x,int l,int r,int p){
        if(l==r) return t[x].nxt;
        // pushdown(x,l,r);//dele?
        if(p<=mid) return fin(t[x].ls,l,mid,p);
        else return fin(t[x].rs,mid+1,r,p);
    }
    void dfs(int u,int len){
    //    cout<<" dfs "<<u<<" len "<<len<<endl;
    //    cout<<" fail "<<fail[u]<<endl;
        //5
        for(reg j=0;j<26;++j) mx[u][j]=mx[fail[u]][j];
        //6
        for(reg i=0;i<26;++i){
            rt[u][i]=rt[fail[u]][i];
        }
        
    
        for(reg o=hd[u];o;o=e[o].nxt){
            int v=e[o].to;
            if(u==0) sx=e[o].x,sc=e[o].c,fc=v;
            int x=e[o].x,c=e[o].c;
    //        cout<<" xx "<<x<<" cc "<<c<<endl;
            ans[v]=ans[u];
            //1
            int t=min(x,mx[u][c]);
    //        cout<<" tt "<<t<<" rt "<<rt[u][c]<<" fai "<<rt[fail[u]][c]<<endl;
            int lp=query(rt[u][c],1,lim,1,x);
    //        cout<<" lp "<<lp<<endl;
            lp=ad((ll)t*(t+1)/2%mod,lp);
            ans[v]=ad(ans[v],lp);
    
            if(t<x&&sc==c){//has nxt=0
                int re=x-t;
                if(u==0){
                    ans[v]=ad(ans[v],(ll)x*(x-1)/2%mod);
                }else{
                    ans[v]=ad(ans[v],(ll)re*sx%mod);
                }
            }
            
            //3
            int fa=fin(rt[fail[u]][c],1,lim,x);
            if(fa!=0){
                fail[v]=fa;
            }else{
    //            cout<<" u "<<u<<" || "<<sc<<" "<<c<<" || "<<x<<" "<<sx<<endl;
                if(u&&sc==c&&x>=sx){
                    fail[v]=fc;
                }else{
                    fail[v]=0;
                }
            }
            //2.1
            int tmp=rt[u][c];
            rt[u][c]=0;
            chan(rt[u][c],tmp,1,lim,1,x,len);
            //2.2
            tmp=rt[u][c];
            rt[u][c]=0;
            upda(rt[u][c],tmp,1,lim,x,v);
            //4
            int od=mx[u][c];
            mx[u][c]=max(mx[u][c],x);
            
    
            dfs(v,len+x);
            //warning 1
            if(u){
                rt[u][c]=rt[fail[u]][c];
                mx[u][c]=od; 
            }else{
                rt[u][c]=0;mx[u][c]=0;
            }
        }
    }
    int main(){
        rd(n);
        int now=0;
        int op,x;char c[233];
        for(reg i=1;i<=n;++i){
            rd(op);
            if(op==1){
                to[i]=i;
                rd(x);scanf("%s",c+1);
    //            cout<<c+1<<endl;
                add(now,i,x,c[1]-'a');
                now=i;
            }else{
                rd(x);
                to[i]=to[x];
                now=to[x];
            }
        }
        dfs(0,0);
    //    prt(ans,1,n);
    //    prt(to,1,n);
        for(reg i=1;i<=n;++i){
            ans[i]=ans[to[i]];
            printf("%d
    ",ans[i]);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */
  • 相关阅读:
    iOS学习笔记(六)——ViewController
    IOS学习笔记(五)——UI基础UIWindow、UIView
    iOS学习笔记(四)——iOS应用程序生命周期
    iOS学习笔记(三)——iOS系统架构
    iOS学习笔记(二)——Hello iOS
    iOS学习笔记(一)——ios搭建开发环境
    Android UI开发第三十篇——使用Fragment构建灵活的桌面
    android实现卸载提示
    Android UI开发第二十六篇——Fragment间的通信
    Android UI开发第二十九篇——Android中五种常用的menu(菜单)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10859444.html
Copyright © 2011-2022 走看看