1600 Simple KMP

对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i)
显然对于一个字符串,如果我们将每个0<=i<=|S|看成一个结点,除了i=0以外i向fail[i]连边,这是一颗树的形状,根是0
我们定义这棵树是G(S),设f(S)是G(S)中除了0号点以外所有点的深度之和,其中0号点的深度为-1
定义key(S)等于S的所有非空子串S'的f(S')之和
给定一个字符串S,现在你要实现以下几种操作:
1.在S最后面加一个字符
2.询问key(S)

善良的出题人不希望你的答案比long long大,所以你需要将答案对1e9+7取模

 
Input
第一行一个正整数Q
Q<=10^5
第二行一个长度为Q的字符串S
Output
输出Q行,第i行表示前i个字符组成的字符串的答案
Input示例
5
abaab
Output示例
0
0
1
4
9
SkyDec (题目提供者)
 
一开始想错了,于是去写LCT+SAM。然后发现竟然撞上正解了......
想法:首先明白只需统计每次加入的点连到每个后缀的Next树的深度,真正的答案可以求前缀和得到。
然后发现Next树的一个节点的深度,其实就是以该点为结尾的后缀能匹配多少前缀(长度长的可以包含短的,连最长的就构成Next树了)。
于是问题变成了以该点为结尾的后缀在原串中出现多少次,这个可以用SAM的parent树的right以及step求出来。
可以使用LCT+SAM,或者离线后树剖维护一下。
突然发现我的LCT比我的树剖快.....
Code
#include < cstdio >

#define gec getchar
#define FILE(F) freopen(F".in","r",stdin),freopen(F".out","w",stdout)
#define DEBUG fprintf(stderr,"Passing [%s] in Line (%d)\n",__FUNCTION__,__LINE__) typedef long long ll;
template
inline void read(T&x)
{
x=0;bool f=0;char c=gec();
for(;c<'0'||c>'9';c=gec())f=(c=='-');
for(;c>='0'&&c<='9';c=gec())x=x*10+c-'0';
x=f?-x:x;
}
const int MAXN(100010),MP(1e9+7);
int n;char str[MAXN]; void plus(int &x,int y){x+=y;x-=x>=MP?MP:0;} namespace Force_LCT
{
struct LCT
{
int nx[2],fa;
int step,right;
int Sum_step,Tag,Sum;//Son need +Tag?
}tr[MAXN<<1]; void swap(int &x,int &y){int t(x);x=y;y=t;}
int which(int x){if(tr[tr[x].fa].nx[0]==x)return 0;if(tr[tr[x].fa].nx[1]==x)return 1;return -1;}
void push(int x)
{
if(!tr[x].Tag)return;
plus(tr[tr[x].nx[0]].Tag,tr[x].Tag); plus(tr[tr[x].nx[0]].right,tr[x].Tag);
plus(tr[tr[x].nx[0]].Sum,(ll)tr[x].Tag*tr[tr[x].nx[0]].Sum_step%MP);
plus(tr[tr[x].nx[1]].Tag,tr[x].Tag); plus(tr[tr[x].nx[1]].right,tr[x].Tag);
plus(tr[tr[x].nx[1]].Sum,(ll)tr[x].Tag*tr[tr[x].nx[1]].Sum_step%MP);
tr[x].Tag=0;
} void update(int x)
{
tr[x].Sum=((ll)tr[x].step*tr[x].right)%MP; tr[x].Sum_step=tr[x].step;
if(tr[x].nx[0])plus(tr[x].Sum,tr[tr[x].nx[0]].Sum),plus(tr[x].Sum_step,tr[tr[x].nx[0]].Sum_step);
if(tr[x].nx[1])plus(tr[x].Sum,tr[tr[x].nx[1]].Sum),plus(tr[x].Sum_step,tr[tr[x].nx[1]].Sum_step);
} void rotate(int x)
{
int fa=tr[x].fa,fafa=tr[fa].fa,fd=which(fa),xd=which(x);
tr[tr[x].nx[xd^1]].fa=fa;
tr[fa].nx[xd]=tr[x].nx[xd^1];
tr[x].nx[xd^1]=fa;tr[fa].fa=x;
tr[x].fa=fafa;if(fd!=-1)tr[fafa].nx[fd]=x;
update(fa);
} int st[MAXN<<1],tp;
void splay(int x)
{
st[tp=1]=x;
for(int t=x;which(t)!=-1;t=tr[t].fa)st[++tp]=tr[t].fa;
while(tp)push(st[tp--]);
while(which(x)!=-1)
{
int fa=tr[x].fa;
if(which(fa)!=-1) rotate( which(x)^which(fa)? fa : x );
rotate(x);
}
update(x);
} void access(int x)
{
for(int t=0;x;t=x,x=tr[x].fa)
{
splay(x); tr[x].nx[1]=t; update(x);
}
} void cut(int x,int y)//x's fa is y
{
access(x); splay(y);
tr[y].nx[1]=0; update(y); tr[x].fa=0;
} void link(int x,int y)//x's fa is y
{
splay(y); tr[x].fa=y;
} } namespace Force_SAM
{
using namespace Force_LCT;
struct SAM
{
int nx[26],pre,step,right;
}sam[MAXN<<1];int top=1,now=1,root=1,last,lastson; void New(int x)
{
tr[x].right=sam[x].right;
tr[x].step=sam[x].step-sam[sam[x].pre].step; update(x);
} void entend(int x,int &S,int num)
{
last=now; now=++top; sam[now].step=sam[last].step+1; sam[now].right=1;
for(;!sam[last].nx[x]&&last;last=sam[last].pre)
sam[last].nx[x]=now;
if(!last)sam[now].pre=root;
else
{
lastson=sam[last].nx[x];
if(sam[lastson].step==sam[last].step+1)sam[now].pre=lastson;
else
{
sam[++top]=sam[lastson]; sam[top].step=sam[last].step+1;
splay(lastson); sam[top].right=sam[lastson].right=tr[lastson].right;
New(top); link(top,sam[top].pre);
cut(lastson,sam[lastson].pre);
sam[now].pre=sam[lastson].pre=top;
New(lastson); link(lastson,sam[lastson].pre);
for(;sam[last].nx[x]==lastson&&last;last=sam[last].pre)
sam[last].nx[x]=top;
}
}
New(now);
link(now,sam[now].pre);
access(now); splay(now);
S=tr[tr[now].nx[0]].Sum;
plus(tr[tr[now].nx[0]].Tag,1); plus(tr[tr[now].nx[0]].right,1);
plus(tr[tr[now].nx[0]].Sum,tr[tr[now].nx[0]].Sum_step);
} int F[MAXN];
void Total()
{
New(1);
for(int i=1;i<=n;i++)
{
entend(str[i]-'a',F[i],i);
plus(F[i],F[i-1]);
}
for(int i=1;i<=n;i++)plus(F[i],F[i-1]);
for(int i=1;i<=n;i++)printf("%d\n",F[i]);
} } int main()
{
read(n);scanf("%s",str+1);
Force_SAM::Total();
return 0;
}

51Nod 1600 Simple KMP SAM+LCT/树链剖分的更多相关文章

  1. 51Nod 1600 Simple KMP 解题报告

    51Nod 1600 Simple KMP 对于一个字符串\(|S|\),我们定义\(fail[i]\),表示最大的\(x\)使得\(S[1..x]=S[i-x+1..i]\),满足\((x<i ...

  2. bryce1010专题训练——LCT&&树链剖分

    LCT&&树链剖分专题 参考: https://blog.csdn.net/forever_wjs/article/details/52116682

  3. 【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1036 lct: (ps:为嘛我的那么慢T_T,不知道排到哪了..难道别人都是树剖吗...看来有必要学 ...

  4. Cogs 1583. [POJ3237]树的维护 LCT,树链剖分

    题目:http://cojs.tk/cogs/problem/problem.php?pid=1583 1583. [POJ3237]树的维护 ★★★☆   输入文件:maintaintree.in  ...

  5. Cogs 1672. [SPOJ375 QTREE]难存的情缘 LCT,树链剖分,填坑计划

    题目:http://cojs.tk/cogs/problem/problem.php?pid=1672 1672. [SPOJ375 QTREE]难存的情缘 ★★★☆   输入文件:qtree.in  ...

  6. bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树

    题目: Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob可能会进 ...

  7. 51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*

    Description 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i&l ...

  8. 51nod 1600 Simple KMP

    又被机房神犇肉丝哥哥和glory踩爆了 首先这个答案的输出方式有点套路,当前的答案=上一个答案+每一个后缀的f值=上一个答案+上一次算的每个后缀的f值+当前每个后缀的深度 这个题意给了个根深度为-1有 ...

  9. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

随机推荐

  1. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_高级管理控制(配置)

    一个应用程序的XML配置文件示例: <?xml version="1.0"?> <configuration> <runtime> <as ...

  2. POJ 3659 Cell Phone Network 最小支配集模板题(树形dp)

    题意:有以个 有 N 个节点的树形地图,问在这些顶点上最少建多少个电话杆,可以使得所有顶点被覆盖到,一个节点如果建立了电话杆,那么和它直接相连的顶点也会被覆盖到. 分析:用最少的点覆盖所有的点,即为求 ...

  3. 百度判断手机终端并自动跳转uaredirect.js代码及使用实例

    百度siteapp下的一款跳转的产品,使用起来很方便.你可以用这款JS跳转到手机版,也可以跳转到任何你想跳转的位置. js代码如下: function uaredirect(f) { try { if ...

  4. nginx配置应用

    启动nginxvim /usr/local/lnmp/nginx/conf/nginx.conf mkdir /wwwcd /wwwvim index.html www.westos.orgmkdir ...

  5. 8.Spring对JDBC的支持和事务

    1.Spring对JDBC的支持 DAO : Spring中对数据访问对象(DAO)的支持旨在简化Spring与数据访问技术的操作,使JDBC.Hibernate.JPA和JDO等采用统一的方式访问 ...

  6. java spi机制和场景

    JDK中查找服务的实现的工具类是:java.util.ServiceLoader, jvm启动时自动查找META-INF/services/下面的实现类,并初始化实例 jdbc的mysql实现类 在静 ...

  7. d题

    #include<iostream>#include<algorithm>using namespace std;int a[200005];int b[200005];int ...

  8. 第八章:BOM

    /* * bom: * 提供了浏览器接口; * w3c为了把javascript最基本的只是标准化已经将bom的主要方面纳入html5规范*/ console.log(window); !(funct ...

  9. 修改虚拟机IP地址

    Linux环境下IP地址配置文件路径: vim  /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE="eth0" BOOTPROTO ...

  10. VUE环境搭建及打包上线

    1.vue2.0新手填坑攻略之使用vue-cli搭建vue项目开发环境到项目发布 https://blog.csdn.net/u010020858/article/details/72865101 2 ...