[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('\n');}

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\n",ans[i]);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

 

posted @ 2019-05-13 22:27  *Miracle*  阅读(406)  评论(0编辑  收藏  举报