[HNOI2019]JOJO(KMP自动机+主席树)
一道神仙题,考察选手对KMP的深入理解。
先考虑没有2操作的做法。设每一段为一个二元组(x,c),考虑一段前缀匹配后缀,除了第一段的字符,其他段的二元组(x,c)必须相等,所以可以将其视为特殊字符进行匹配。在串末尾加入(x,c)时,显然不断跳next数组,如果当前前缀后接的字符为c ,那么可以增加一段首项为当前前缀长度,然后发现这一段的next数组为首项为前缀长度,公差为1的等差数列。next链上如果有等于(x,c)的二元组,则next指向二元组,否则指向0,因为如果存在(y,c)满足y>x,则一定无法匹配。
解决了没有2操作的做法,考虑有2操作,由于KMP复杂度是均摊的,很显然不能直接在树上dfs,所以要优化求next过程。考虑离线建树,dfs时维护每条next链上的KMP自动机,f[i][j][k]表示状态i下加入二元组(j,k)next指向哪,g[i][j][k]表示产生的贡献,每次修改复制前一次的f数组,修改f[i][x][c],g[i][x][1...c]为等差数列,此处可以用主席树实现。
#include<bits/stdc++.h> #define lson l,mid,tr[rt].lc #define rson mid+1,r,tr[rt].rc using namespace std; const int N=1e5+10,M=1e4+7,mod=998244353; struct node{int lc,rc,sum,lazy,nxt;}tr[N*60]; int n,tot,top,val[N],pos[N],ans[N],a[N],b[N],rt[N][26],mx[N][26]; vector<int>G[N]; void newnode(int&x){tr[++tot]=tr[x],x=tot;} void add(int x,int v,int len){tr[x].sum=1ll*v*len%mod,tr[x].lazy=v;} int S(int x){return 1ll*x*(x+1)/2%mod;} void pushdown(int l,int r,int rt) { if(!tr[rt].lazy)return; int mid=l+r>>1; newnode(tr[rt].lc),add(tr[rt].lc,tr[rt].lazy,mid-l+1); newnode(tr[rt].rc),add(tr[rt].rc,tr[rt].lazy,r-mid); tr[rt].lazy=0; } void update(int k,int v,int p,int l,int r,int&rt) { newnode(rt); if(r<k){add(rt,v,r-l+1);return;} if(l==r){tr[rt].nxt=p,add(rt,v,1);return;} pushdown(l,r,rt); int mid=l+r>>1; update(k,v,p,lson); if(k>mid)update(k,v,p,rson); tr[rt].sum=(tr[tr[rt].lc].sum+tr[tr[rt].rc].sum)%mod; } void query(int k,int&ans,int&nxt,int l,int r,int&rt) { if(r<k){ans=(ans+tr[rt].sum)%mod;return;} if(l==r){ans=(ans+tr[rt].sum)%mod,nxt=tr[rt].nxt;return;} pushdown(l,r,rt); int mid=l+r>>1; query(k,ans,nxt,lson); if(k>mid)query(k,ans,nxt,rson); } void dfs(int u) { ++top; int x=val[u]/M,y=val[u]%M,nxt=0; a[top]=val[u],b[top]=b[top-1]+y; if(top==1)ans[u]=S(y-1); else{ ans[u]=(ans[u]+S(min(mx[top][x],y)))%mod; query(y,ans[u],nxt,1,M,rt[top][x]); if(!nxt&&a[1]/M==x&&b[1]<y)nxt=1,ans[u]=(ans[u]+1ll*b[1]*max(0,y-mx[top][x]))%mod; } mx[top][x]=max(mx[top][x],y); update(y,b[top-1],top,1,M,rt[top][x]); for(int i=0;i<G[u].size();i++) { memcpy(mx[top+1],mx[nxt+1],sizeof mx[top+1]); memcpy(rt[top+1],rt[nxt+1],sizeof rt[top+1]); ans[G[u][i]]=ans[u],dfs(G[u][i]); } --top; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int op,x; scanf("%d%d",&op,&x); if(op==1) { char c;cin>>c; val[++tot]=(c-'a')*M+x,pos[i]=tot,G[pos[i-1]].push_back(pos[i]); } else pos[i]=pos[x]; } for(int i=0;i<G[0].size();i++) { tot=0; memset(rt[1],0,sizeof rt[1]); memset(mx[1],0,sizeof mx[1]); dfs(G[0][i]); } for(int i=1;i<=n;i++)printf("%d\n",ans[pos[i]]); }