不错的好题

有一个比较弱化的问题:

[题集]串

已知小串的子串问题,例题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 pushdownif(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;//5for(reg j=0;j<26;++j) mx[u][j]=mx[fail[u]][j];//6for(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];//1int 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=0int 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);}}//3int 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.1int tmp=rt[u][c];rt[u][c]=0;chan(rt[u][c],tmp,1,lim,1,x,len);//2.2tmp=rt[u][c];rt[u][c]=0;upda(rt[u][c],tmp,1,lim,x,v);//4int od=mx[u][c];mx[u][c]=max(mx[u][c],x);dfs(v,len+x);//warning 1if(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*
*/

转载于:https://www.cnblogs.com/Miracevin/p/10859444.html

[HNOI2019]JOJO相关推荐

  1. 【CF917E】Upside Down(哈希二分)(后缀数组)(AC自动机)

    传送门 诈尸,主要是最近一直在刷水题感觉没有什么值得写的. 口胡好题,不建议写. 题解: 一句话说,将出现的情况分为在 u-LCA链上 和横跨LCA 分别统计. 在链上的可以直接建立正反AC自动机,然 ...

  2. Loj #3055. 「HNOI2019」JOJO

    Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...

  3. LOJ 3055 「HNOI2019」JOJO—— kmp自动机+主席树

    题目:https://loj.ac/problem/3055 先写了暴力.本来想的是 n<=300 的那个在树上暴力维护好整个字符串, x=1 的那个用主席树维护好字符串和 nxt 数组.但 x ...

  4. 【LOJ3055】「HNOI2019」JOJO

    [题目链接] 点击打开链接 [思路要点] 考虑将字符串缩成若干个相同字符的段 (cnt,char)(cnt,char)(cnt,char) ,相邻的字符不相同. 考虑一个与某一个前缀匹配的后缀,若该后 ...

  5. 万物皆可JOJO:这个GAN直接让马斯克不做人啦 !Demo在线可玩!

    来源:量子位 这下真的是万物皆可JOJO化了! 本来就神采飞扬的马斯克,下一刻更是仿佛要直接"我不做人啦!" 世界名画蒙娜丽莎神秘优雅的微笑,似乎也变得JO灼了起来-- 再来个同一 ...

  6. 万物皆可JOJO:这个GAN直接让马斯克不做人啦 | Demo可玩

    博雯 发自 凹非寺 量子位 报道 | 公众号 QbitAI 这下真的是万物皆可JOJO化了! 本来就神采飞扬的马斯克,下一刻更是仿佛要直接"我不做人啦!" 世界名画蒙娜丽莎神秘优雅 ...

  7. HNOI2019 退役记

    窗外风雨大作. 凌晨两点又被噩梦惊醒,朦胧中看见书桌的灯还亮着. 走近书桌,有一个人正在敲打着键盘,屏幕上是一些似曾相识的东西. 被水浸湿的头发随意地搭在额头上,鼻梁上架着一副眼镜,镜片上全是小水珠, ...

  8. HNOI2019爆零记

    HNOI2019真-爆零祭 我怎么这么菜QAQ day-37 从学科溜过来搞OI. 班主任一直在谈论我退役的事情,这就是NOIP挂分的后果...说我没考好就找理由,人家xxxxxxx可不是xxxxxx ...

  9. Python编曲实践(八):我,乔鲁诺·乔巴那,能用两百行代码写出JOJO黄金之风里我自己的出场曲!

    前言 前些天笔者写的文章 Python编曲实践(七):整整一百行Python代码写出黑人抬棺梗曲<Astronomia>的旋律 受到了大家的许多支持和好评,本篇文章挑战更复杂.更有挑战性, ...

最新文章

  1. kaldi上第一个免费的中文语音识别例子
  2. Linux动态频率调节系统CPUFreq之一:概述【转】-- 非常好的博客
  3. Leave List-Processing 新解
  4. Nacos源码BeatTask
  5. Gradle实战:发布aar包到maven仓库
  6. MySql某一列累计查询
  7. iOS Abort问题系统性解决方案
  8. tp3.2 mysql elt出错_ThinkPHP3.2.3 SQL注入漏洞分析
  9. mysql实际是用命令还是图形化_那些你不常用却非常有用的MySql语句和命令
  10. VC2015运行库安装失败
  11. 计算机病毒学,计算机病毒学.doc
  12. 奥地利邮政服务推出加密收藏邮票
  13. 如何用excel做正交分析_利用Excel进行正交设计及分析
  14. 计算机ipv6无法连接,ipv6无网络访问权限实测解决教程
  15. 机器学习在信用评分卡中的应用
  16. 听李天飞《大话西游》有感
  17. 域名解析暂时失败(二)
  18. python分形曲线代码_Python:绘制L-System的分形图
  19. 2023年美业市场五大消费趋势
  20. Unity之简单射击游戏案例

热门文章

  1. linux如何用vi编程,vi使用方法
  2. httpposterror_http请求405错误方法不被允许的解决 (Method not allowed)
  3. 小乌龟游泳java_乌龟翻身那么痛苦,它们为什么还没有灭绝?
  4. NR-ARFCN和频率之间换算
  5. sql 找到上一次_记一次对XXCMS的代码审计
  6. FPGA设计心得(9)基于DDS IP核的任意波形发生器设计
  7. 基本电路元件和特性(1)电阻基础(R)
  8. 【 C 】经典抽象数据类型(ADT)之内存分配
  9. 转另一个获取硬盘序列号的方法
  10. GTK+重拾--08 GTK+中的对话框