一道神仙题,考察选手对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+,M=1e4+,mod=;
struct node{int lc,rc,sum,lazy,nxt;}tr[N*];
int n,tot,top,val[N],pos[N],ans[N],a[N],b[N],rt[N][],mx[N][];
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+)/%mod;}
void pushdown(int l,int r,int rt)
{
if(!tr[rt].lazy)return;
int mid=l+r>>;
newnode(tr[rt].lc),add(tr[rt].lc,tr[rt].lazy,mid-l+);
newnode(tr[rt].rc),add(tr[rt].rc,tr[rt].lazy,r-mid);
tr[rt].lazy=;
}
void update(int k,int v,int p,int l,int r,int&rt)
{
newnode(rt);
if(r<k){add(rt,v,r-l+);return;}
if(l==r){tr[rt].nxt=p,add(rt,v,);return;}
pushdown(l,r,rt);
int mid=l+r>>;
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>>;
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=;
a[top]=val[u],b[top]=b[top-]+y;
if(top==)ans[u]=S(y-);
else{
ans[u]=(ans[u]+S(min(mx[top][x],y)))%mod;
query(y,ans[u],nxt,,M,rt[top][x]);
if(!nxt&&a[]/M==x&&b[]<y)nxt=,ans[u]=(ans[u]+1ll*b[]*max(,y-mx[top][x]))%mod;
}
mx[top][x]=max(mx[top][x],y);
update(y,b[top-],top,,M,rt[top][x]);
for(int i=;i<G[u].size();i++)
{
memcpy(mx[top+],mx[nxt+],sizeof mx[top+]);
memcpy(rt[top+],rt[nxt+],sizeof rt[top+]);
ans[G[u][i]]=ans[u],dfs(G[u][i]);
}
--top;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int op,x;
scanf("%d%d",&op,&x);
if(op==)
{
char c;cin>>c;
val[++tot]=(c-'a')*M+x,pos[i]=tot,G[pos[i-]].push_back(pos[i]);
}
else pos[i]=pos[x];
}
for(int i=;i<G[].size();i++)
{
tot=;
memset(rt[],,sizeof rt[]);
memset(mx[],,sizeof mx[]);
dfs(G[][i]);
}
for(int i=;i<=n;i++)printf("%d\n",ans[pos[i]]);
}

[HNOI2019]JOJO(KMP自动机+主席树)的更多相关文章

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

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

  2. NOI 2011 阿狸的打字机(AC自动机+主席树)

    题意 https://loj.ac/problem/2444 思路 ​多串匹配,考虑 \(\text{AC}\) 自动机.模拟打字的过程,先建出一棵 \(\text{Trie}\) 树,把它变成自动机 ...

  3. Bzoj2534:后缀自动机 主席树启发式合并

    国际惯例的题面:考虑我们求解出字符串uvu第一个u的右端点为i,第二个u的右端点为j,我们需要满足什么性质?显然j>i+L,因为我们选择的串不能是空串.另外考虑i和j的最长公共前缀(也就是说其p ...

  4. luogu P5826 【模板】子序列自动机 主席树 vector 二分

    LINK:子序列自动机 想了一些很有趣的做法. dp 容易看出 f[i][j]表示前i个数匹配了j个数的dp 不过复杂度很高. 贪心 容易想到匹配的时候每个数字尽量往前匹配 这样显然是最优的 复杂度Q ...

  5. CodeForces 547E Mike and Friends AC自动机 主席树

    题意: 给出\(n\)个字符串\(s_i\)和\(q\)个询问: \(l,r,k\):\(\sum\limits_{i=l}^{r}count(i, k)\),其中\(count(i,j)\)表示\( ...

  6. 【洛谷5287】[HNOI2019] JOJO(主席树优化KMP)

    点此看题面 大致题意: 每次往一个字符串末尾加上\(x\)个字符\(c\),或者回到某一历史版本,求\(KMP\)的\(\sum Next_i\). 问题转化 考虑到可以离线. 于是,我们就可以用一个 ...

  7. 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 657  Solved: 274[Su ...

  8. CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)

    What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...

  9. CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)

    What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...

随机推荐

  1. 全面掌握Nginx配置+快速搭建高可用架构 一 开启status页面检测服务状态

    输入命令Nginx -V 打开conf.d/default.conf 配置模块,配置位置在server或者location 配置完成后测试语法正确 nginx -tc /etc/nginx/nginx ...

  2. 文献阅读报告 - 3DOF Pedestrian Trajectory Prediction

    文献 Sun L , Yan Z , Mellado S M , et al. 3DOF Pedestrian Trajectory Prediction Learned from Long-Term ...

  3. 自己整理的常用SQL Server 2005 语句、

    --创建数据库 create database 数据库 go --打开数据库 use 数据库 --删除数据库 drop database 数据库 Go --创建数据表 create table 数据表 ...

  4. 8.scrapy的第一个实例

    [目标]要完成的任务如下: ※ 创建一个 Scrap项目.※ 创建一个 Spider来抓取站点和处理数据.※ 通过命令行将抓取的内容导出.※ 将抓取的内容保存的到 MongoDB数据库.======= ...

  5. SQL审核平台-Yearning安装部署实践

    相关文档: https://guide.yearning.io/ yearning简介 http://python.yearning.io/install/  yearning安装 Yearning ...

  6. 吴裕雄--天生自然TensorFlow2教程:张量限幅

    import tensorflow as tf a = tf.range(10) a # a中小于2的元素值为2 tf.maximum(a, 2) # a中大于8的元素值为8 tf.minimum(a ...

  7. SASS - 简介

    SASS – 简介 SASS – 环境搭建 SASS – 使用Sass程序 SASS – 语法 SASS – 变量 SASS- 局部文件(Partial) SASS – 混合(Mixin) SASS ...

  8. python进阶(三)~~~装饰器和闭包

    一.闭包 满足条件: 1. 函数内嵌套一个函数: 2.外层函数的返回值是内层函数的函数名: 3.内层嵌套函数对外部作用域有一个非全局变量的引用: def func(): print("=== ...

  9. 五年Java经验,面试还是说不出日志该怎么写更好?——日志规范与最佳实践篇

    本文是一个系列,欢迎关注 查看上一篇文章可以扫描文章下方的二维码,点击往期回顾-日志系列即可查看所有相关文章 概览 上一篇我们讨论了为什么要使用日志框架,这次我们深入问题的根源,为什么我们需要日志? ...

  10. CodeForces 1000B Light It Up(贪心、思维)

    https://codeforces.com/problemset/problem/1000/B 题意: 一个模拟思维题.就是有一盏灯,0时刻开着.n次操作,你可以在其中加入一次操作(或者不加),操作 ...