[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+,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自动机+主席树)的更多相关文章
- LOJ 3055 「HNOI2019」JOJO—— kmp自动机+主席树
题目:https://loj.ac/problem/3055 先写了暴力.本来想的是 n<=300 的那个在树上暴力维护好整个字符串, x=1 的那个用主席树维护好字符串和 nxt 数组.但 x ...
- NOI 2011 阿狸的打字机(AC自动机+主席树)
题意 https://loj.ac/problem/2444 思路 多串匹配,考虑 \(\text{AC}\) 自动机.模拟打字的过程,先建出一棵 \(\text{Trie}\) 树,把它变成自动机 ...
- Bzoj2534:后缀自动机 主席树启发式合并
国际惯例的题面:考虑我们求解出字符串uvu第一个u的右端点为i,第二个u的右端点为j,我们需要满足什么性质?显然j>i+L,因为我们选择的串不能是空串.另外考虑i和j的最长公共前缀(也就是说其p ...
- luogu P5826 【模板】子序列自动机 主席树 vector 二分
LINK:子序列自动机 想了一些很有趣的做法. dp 容易看出 f[i][j]表示前i个数匹配了j个数的dp 不过复杂度很高. 贪心 容易想到匹配的时候每个数字尽量往前匹配 这样显然是最优的 复杂度Q ...
- CodeForces 547E Mike and Friends AC自动机 主席树
题意: 给出\(n\)个字符串\(s_i\)和\(q\)个询问: \(l,r,k\):\(\sum\limits_{i=l}^{r}count(i, k)\),其中\(count(i,j)\)表示\( ...
- 【洛谷5287】[HNOI2019] JOJO(主席树优化KMP)
点此看题面 大致题意: 每次往一个字符串末尾加上\(x\)个字符\(c\),或者回到某一历史版本,求\(KMP\)的\(\sum Next_i\). 问题转化 考虑到可以离线. 于是,我们就可以用一个 ...
- 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 657 Solved: 274[Su ...
- CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...
- CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...
随机推荐
- centos7 lvm合并分区脚本初探-linux性能测试 -centos7修改网卡名字-jdk环境安装脚本-关键字查询文件-批量添加用户
1.#!/bin/bash lvmdiskscan | grep centos > /root/a.txt a=`sed -n '1p' /root/a.txt` b=`sed -n '2p' ...
- LIS是什么?【质量控制】
继续[LIS是什么?]中提到的[质量控制]. Ⅱ.质量控制要求非常专业,现在只说一说个人理解,以下仅为LIS检验中部分理解,实际上实验室质量控制还包含的报告时效,实验室温度.湿度等等一系列内容,是一个 ...
- LeetCode做题笔记之动态规划
LeetCode之动态规划 时间有限只做了下面这几道:70.338.877.96.120.95.647,后续会继续更新 70:爬楼梯 先来道简单的练练手,一道经典的动态规划题目 可以采用动态规划的备忘 ...
- 使用 this 关键字定义方法和属性
1.方法和属性的定义 属性是类中声明的变量,与其他地方变量的声明基本相同,只是属性必须 this 关键字,并且这里没有var 关键字. this.age; 在使用时,先是 this 关键字,之后的点语 ...
- offsetof宏与container_of宏
offsetof宏与container_of宏1.由结构体指针进而访问各元素的原理(1)通过结构体整体变量来访问其中各个元素,本质上是通过指针方式来访问的,形式上是通过.的方式来访问的(这个时候其实是 ...
- Centos下nginx安装
安装很简单,这里记录只是为了记下下载地址: A.[root@localhost soft]# wget http://nginx.org/download/nginx-1.4.2.tar.gz B.[ ...
- JavaScript-数据类型和变量
数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定 ...
- dp--区间dp P1880 [NOI1995]石子合并
题目描述 在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出一个算法,计算出将 N 堆石子 ...
- 小程序调用wx.chooseLocation接口的时候无法获取权限(ios)
ios手机小程序调用wx.chooseLocation接口的时候,获取权限的时候报authorize:fail:require permission desc这样子的错误,这是由于苹果的安全机制导致需 ...
- VUE- iView组件框架的使用
VUE- iView组件框架的使用 1. 下载iView 工程. 引用:https://www.iviewui.com/