51Nod 1600 Simple KMP
来源:互联网 发布:反骨是什么网络用语 编辑:程序博客网 时间:2024/05/20 05:30
SAM+LCT/树剖线段树
一个点的深度就是有多少个以这个点结尾的后缀等于前缀。fail树性质不太够,不好下手,直接考虑答案的贡献。对于两个相等的区间[l,r]&[x,y]其中l
#include<cstdio>#include<cstring>#include<iostream>#define N 100005#define MOD 1000000007#define A 28#define pr(_i) cout<<#_i<<" = "<<_i<<endlusing namespace std;namespace runzhe2000{ typedef long long ll; int n, ecnt, last[N<<1], q[N], top[N<<1], siz[N<<1], son[N<<1], dep[N<<1], fa[N<<1], beg[N<<1], rebeg[N<<1], timer; char s[N]; struct edge{int next, to;}e[N<<1]; void addedge(int a, int b) { e[++ecnt] = (edge){last[a], b}; last[a] = ecnt; } struct SAM { SAM *fail, *next[A]; int len; }mem[N<<1], *tot, *null, *lastp, *root; SAM *newSAM(){SAM *p = ++tot; *p = *null; return p;} void init_SAM() { null = tot = mem; null->fail = null; for(int i = 0; i < A; i++) null->next[i] = null; lastp = root = newSAM(); } void extend(int v) { SAM *p = lastp, *np = newSAM(); lastp = np; np->len = p->len + 1; for(; p->next[v] == null && p != null; p = p->fail) p->next[v] = np; if(p == null) np->fail = root; else { SAM *q = p->next[v]; if(p->len + 1 == q->len)np->fail = q; else { SAM *nq = newSAM(); nq->len = p->len + 1; memcpy(nq->next, q->next, sizeof(q->next)); nq->fail = q->fail; q->fail = np->fail = nq; for(; p->next[v] == q && p != null; p = p->fail) p->next[v] = nq; } } } struct seg { int sum, tag1, tag2, lazy; }t[N*8]; void pushup(int x) { t[x].sum = (t[x<<1].sum + t[x<<1|1].sum) % MOD; t[x].tag1 = (t[x<<1].tag1 + t[x<<1|1].tag1) % MOD; t[x].tag2 = (t[x<<1].tag2 + t[x<<1|1].tag2) % MOD; } void build(int x, int l, int r) { if(l == r){t[x].tag1 = -(t[x].tag2 = mem[rebeg[l]].len - mem[rebeg[l]].fail->len); return;} int mid = (l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void add(int x, int c) { (t[x].sum += ((ll)t[x].tag2*c%MOD*c%MOD + (ll)t[x].tag1*c%MOD)*(MOD-MOD/2)%MOD) %= MOD; (t[x].tag1 += (ll)t[x].tag2*c%MOD*2%MOD) %= MOD; (t[x].lazy += c) %= MOD; } void pushdown(int x) { if(!t[x].lazy) return; add(x<<1,t[x].lazy); add(x<<1|1,t[x].lazy); t[x].lazy = 0; } void modi(int x, int l, int r, int ql, int qr, int c) { if(ql <= l && r <= qr) return (void)add(x,c); int mid = (l+r)>>1; pushdown(x); if(ql <= mid) modi(x<<1,l,mid,ql,qr,c); if(mid < qr) modi(x<<1|1,mid+1,r,ql,qr,c); pushup(x); } void dfs1(int x) { dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == fa[x]) continue; fa[y] = x; dfs1(y); siz[x] += siz[y]; siz[y] > siz[son[x]] ? son[x] = y : 0; } } void dfs2(int x) { rebeg[beg[x] = ++timer] = x; top[x] = son[fa[x]] == x ? top[fa[x]] : x; if(son[x]) dfs2(son[x]); for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == fa[x] || y == son[x]) continue; dfs2(y); } } void main() { scanf("%d%s",&n,s+1); init_SAM(); for(int i = 1; i <= n; i++) { extend(s[i] - 'a'); q[i] = lastp - mem; } for(SAM *i = tot; i != mem; i--) addedge(i->fail - mem, i - mem); dfs1(1); dfs2(1); int totmem = tot-mem; build(1,1,totmem); int ans = 0; for(int i = 1; i <= n; i++) { int x = q[i]; for(; x; x = fa[top[x]]) modi(1,1,totmem,beg[top[x]],beg[x], 1); (ans += t[1].sum) %= MOD; printf("%d\n",(ans+MOD)%MOD); } }}int main(){ runzhe2000::main();}
0 0
- 51Nod 1600 Simple KMP
- 51nod 1600 Simple KMP 后缀自动机+树链剖分+线段树
- 51Nod 算法马拉松17 Simple KMP 链剖维护SAM的fail树
- 51nod-1277 字符串中的最大值(KMP)
- kmp-51nod 1277 字符串中的最大值
- 51 nod 1277 字符串中的最大值(KMP)
- 51nod 1277 字符串中的最大值(KMP)
- [KMP next树] 51Nod 1277 字符串中的最大值
- 51NOD 1277 字符串中的最大值 【拓展KMP】
- 51NOD 1554 欧姆诺姆和项链 【kmp】
- 【KMP next树】51nod 1277 字符串中的最大值
- 51nod 1277 字符串中的最大值【KMP算法】【next树】
- 51nod 1304 字符串的相似度 拓展kmp
- 51nod 1277 字符串中的最大值(kmp)
- 【Kmp求字符串前缀在字符串出现的次数】51nod 1277 字符串中的最大值
- 51Nod 1277 字符串中的最大值 KMP next数组经典应用
- 51Nod
- 51Nod
- commons-fileupload上传文件(图片)时路径写入数据库时斜杠的问题
- 教你一天玩转JavaScript(四)——使用JavaScript实现定时弹出广告定时隐藏广告
- 洛谷 3338 [ZJOI2014]力
- Lake Counting(POJ 2386)
- java 学习小笔记 (一)
- 51Nod 1600 Simple KMP
- MYSQL错误代码#1045 Access denied for user 'root'@'localhost'
- [转]中英文停止词表(stopword)
- Hibernate知识整理2----4种查询方法
- 用spring+springMVC+mybatis实现模拟秒杀项目(一)
- c语言指针
- HDU 2138 How many prime numbers
- jsp指令与动作
- linux文件的打包与压缩