[HNOI2019]JOJO

https://www.luogu.org/problemnew/show/P5287

题解

可持久化\(KMP\)

那个退回操作我们可以把它看做在操作树上\(dfs\),所以我们可以先把这个树弄出来。

对于连续一段串的匹配问题。

我们可以搞个\(KMP\)自动机,输入当前节点编号也就是\(nxt\),输入下一段连续的字符串,输出\(nxt\)跳完之后的值。

然后我们可以把这个字符串的\(fail\)树弄出来,然后把它搞成一个主席树,相当于是我们令\(ch[now][c][len]\)为这个自动机,第三维比较大,用线段树维护,然后\(dfs\)这颗操作树的时候顺便维护这个节点的\(nxt\),这个点的主席树从fail节点继承。

还要维护从这个点到\(fail\)树根的一条链上\(x\)字符的最长长度,还要在线段树上维护匹配时产生的贡献。

注意特判一些情况比如说开头结尾的字符时一样的。

代码

#include<bits/stdc++.h>
#define mm make_pair
#define P pair<int,int>
#define ls tr[cnt].l
#define rs tr[cnt].r
#define N 100009
using namespace std;
typedef long long ll;
const int M=10001;
vector<int>vec[N];
const int mod=998244353;
int tot,head[N],rt[N][26],mx[N][26],pos[N],tag,top,n,tott,len[N];
P rec[N];
ll ans[N];
inline ll rd(){
  ll x=0;char c=getchar();bool f=0;
  while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
  return f?-x:x;
}
struct node{
  int l,r,nxt;
  ll sum,la;
}tr[N*30];
inline void MOD(ll &x){x=x>=mod?x-mod:x;}
inline int newnode(int pre){
  ++tott;
  tr[tott]=tr[pre];
  return tott;
}
inline void pushdown(int cnt,int l1,int l2){
   ls=newnode(ls);
   MOD(tr[ls].sum=l1*tr[cnt].la%mod);
   rs=newnode(rs);
   MOD(tr[rs].sum=l2*tr[cnt].la%mod);
   tr[ls].la=tr[rs].la=tr[cnt].la;
   tr[cnt].la=0;
}
void query(int cnt,int l,int r,int R,ll &ans,int &nxt){
  if(r<R){
    MOD(ans+=tr[cnt].sum);
    return;
  }
  if(l==r){
    MOD(ans+=tr[cnt].sum);
    nxt=tr[cnt].nxt;
    return;
  }
  int mid=(l+r)>>1;
  if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
  query(ls,l,mid,R,ans,nxt);
  if(mid<R)query(rs,mid+1,r,R,ans,nxt);
}
void upd(int &cnt,int l,int r,int R,int x,int nxt){
    cnt=newnode(cnt);
    if(r<R){
      MOD(tr[cnt].sum=1ll*(r-l+1)*x%mod);
      MOD(tr[cnt].la=x);
      return;
    }
    if(l==r){
      MOD(tr[cnt].sum=1ll*(r-l+1)*x%mod);
      tr[cnt].nxt=nxt;
      return; 
    }
    int mid=(l+r)>>1;
    if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
    upd(ls,l,mid,R,x,nxt);
    if(mid<R)upd(rs,mid+1,r,R,x,nxt);
    MOD(tr[cnt].sum=tr[ls].sum+tr[rs].sum);
}
inline ll calc(ll x){return ((x*(x+1))/2)%mod;}
void dfs(int u){
  ++top;
  int x=rec[u].first,y=rec[u].second;
  if(top==1)tag=x;
  int nxt=0;
  len[top]=len[top-1]+y;
  if(top==1){ans[u]=calc(y-1);}
  else{
    MOD(ans[u]+=calc(min(mx[top][x],y)));
    query(rt[top][x],1,M,y,ans[u],nxt);
    if(!nxt&&tag==x&&len[1]<y){
      nxt=1;
      (ans[u]+=len[1]*max(0,y-mx[top][x]))%=mod;
    }
  }
  mx[top][x]=max(mx[top][x],y);
  upd(rt[top][x],1,M,y,len[top-1],top);
  for(vector<int>::iterator it=vec[u].begin();it!=vec[u].end();++it){
    int v=*it;
    ans[v]=ans[u];
    memcpy(mx[top+1],mx[nxt+1],sizeof(mx[top+1]));
    memcpy(rt[top+1],rt[nxt+1],sizeof(rt[top+1]));
    dfs(v);
  }
  --top;
}
int main(){
  n=rd();
  int opt,x;
  for(int i=1;i<=n;++i){
    opt=rd();x=rd();
    if(opt==1){
      char c;
      cin>>c;
      rec[++tot]=mm(c-'a',x);
      pos[i]=tot;
      vec[pos[i-1]].push_back(pos[i]);   
    }
    else{
      pos[i]=pos[x];
    }
  }
  for(vector<int>::iterator it=vec[0].begin();it!=vec[0].end();++it){
    int v=*it;
    tott=0;
    memset(rt[1],0,sizeof(rt[1]));
    memset(mx[1],0,sizeof(mx[1]));
    dfs(v);
  }
  for(int i=1;i<=n;++i)printf("%d\n",ans[pos[i]]);
  return 0;
}
posted @ 2019-05-28 21:44  comld  阅读(301)  评论(0编辑  收藏  举报