JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
来源:互联网 发布:淘宝苹果id代充 编辑:程序博客网 时间:2024/05/21 06:55
题目大意
有
解题思路
看到这种多串匹配为问题,我们可以考虑用
我们对于每个
注意:
1.
2. 如果不构
程序
//YxuanwKeith#include <cstring>#include <cstdio>#include <algorithm>#include <vector>using namespace std;const int MAXN = 1e6 + 5;struct Sam { int Len, Root, Pre, Go[3];} A[MAXN];struct Trie { int Go[2], Root;} Tri[MAXN];struct Tree { int l, r, Sum;} Tr[MAXN * 20];struct Query { int l, r, bel; Query(int a, int b, int c) {l = a, r = b, bel = c;} Query() {}};vector<Query> Q[MAXN];int Lst, lst, Sum, num, Cnt, tot, QQ, N, Root, Get, Side, Ans[MAXN], Ord[MAXN];char S[MAXN];void Read(int &x) { char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); x = 0; while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}void Sam_Push(int l, int r, int bel, int len) { if (Get < len) return; Q[Side].push_back(Query(l, r, bel));}void Sam_Go(int c) { for (; lst != Root && !A[lst].Go[c]; lst = A[lst].Pre, Get = A[lst].Len); if (A[lst].Go[c]) lst = A[lst].Go[c], Get ++; Side = lst;}void Prepare() { for (int i = 1; i <= QQ; i ++) { int l, r; Read(l), Read(r); scanf("%s", S + 1); lst = Root, Get = Side = 0; int Len = strlen(S + 1); for (int j = 1; j <= Len; j ++) Sam_Go(S[j] - 'a'); Sam_Push(l, r, i, Len); }}int Sam_Add(int lst, int c, int Rt) { int np = ++ tot, p = lst; A[np].Len = A[lst].Len + 1; A[np].Root = Rt; for (; p && !A[p].Go[c]; p = A[p].Pre) A[p].Go[c] = np; if (!p) A[np].Pre = Root; else { int q = A[p].Go[c]; if (A[q].Len == A[p].Len + 1) A[np].Pre = q; else { int nq = ++ tot; A[nq] = A[q], A[nq].Root = 0; A[nq].Len = A[p].Len + 1; A[np].Pre = A[q].Pre = nq; for (; p && A[p].Go[c] == q; p = A[p].Pre) A[p].Go[c] = nq; } } return np;}void Sort() { static int tax[MAXN]; memset(tax, 0, sizeof tax); for (int i = 1; i <= tot; i ++) tax[A[i].Len] ++; for (int i = 1; i <= tot; i ++) tax[i] += tax[i - 1]; for (int i = tot; i; i --) Ord[tax[A[i].Len] --] = i; }void Tr_Merge(int &Rt, int rt, int ot, int l, int r) { Rt = ++ Cnt; if (!rt) {Tr[Rt] = Tr[ot]; return;} if (!ot) {Tr[Rt] = Tr[rt]; return;} if (l == r) { Tr[Rt].Sum = max(Tr[ot].Sum, Tr[rt].Sum); return; } int Mid = (l + r) >> 1; Tr_Merge(Tr[Rt].l, Tr[rt].l, Tr[ot].l, l, Mid), Tr_Merge(Tr[Rt].r, Tr[rt].r, Tr[ot].r, Mid + 1, r); Tr[Rt].Sum = Tr[Tr[Rt].l].Sum + Tr[Tr[Rt].r].Sum; }void Tr_Add(int &Rt, int rt, int l, int r, int Side) { Rt = ++ Cnt; if (rt) Tr[Rt] = Tr[rt]; if (l == r) { Tr[Rt].Sum = 1; return; } int Mid = (l + r) >> 1; if (Side <= Mid) Tr_Add(Tr[Rt].l, Tr[Rt].l, l, Mid, Side); else Tr_Add(Tr[Rt].r, Tr[Rt].r, Mid + 1, r, Side); Tr[Rt].Sum = Tr[Tr[Rt].l].Sum + Tr[Tr[Rt].r].Sum;}void Tr_Query(int Rt, int l, int r, int lx, int rx) { if (!Rt) return; if (rx < l || lx > r) return; if (l >= lx && r <= rx) { Sum += Tr[Rt].Sum; return; } int Mid = (l + r) >> 1; Tr_Query(Tr[Rt].l, l, Mid, lx, rx), Tr_Query(Tr[Rt].r, Mid + 1, r, lx, rx);}void Solve() { Sort(); for (int i = tot; i; i --) { int Now = Ord[i]; Tr_Merge(A[A[Now].Pre].Root, A[Now].Root, A[A[Now].Pre].Root, 1, N); } for (int i = 1; i <= tot; i ++) { for (int j = 0; j < Q[i].size(); j ++) { int l = Q[i][j].l, r = Q[i][j].r, bel = Q[i][j].bel; Sum = 0; Tr_Query(A[i].Root, 1, N, l, r); Ans[bel] = Sum; } } for (int i = 1; i <= QQ; i ++) printf("%d\n", Ans[i]);}void Trie_Add(int bel, int c) { if (!Tri[Lst].Go[c]) Tri[Lst].Go[c] = ++ num; Lst = Tri[Lst].Go[c]; Tr_Add(Tri[Lst].Root, Tri[Lst].Root, 1, N, bel);}void Sam_Build() { static int D[MAXN][2], top = 1; D[1][0] = 1, D[1][1] = 1; for (int i = 1; i <= top; i ++) { for (int j = 0; j < 2; j ++) { if (!Tri[D[i][1]].Go[j]) continue; int v = Tri[D[i][1]].Go[j]; D[++ top][0] = Sam_Add(D[i][0], j, Tri[v].Root); D[top][1] = v; } }}int main() { scanf("%d%d", &N, &QQ); Root = tot = lst = Lst = num = 1; for (int i = 1; i <= N; i ++) { scanf("\n%s", S + 1); int Len = strlen(S + 1); Lst = 1; for (int j = 1; j <= Len; j ++) Trie_Add(i, S[j] - 'a'); } Sam_Build(); Prepare(); Solve();}
1 0
- JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
- Codeforces 666E Forensic Examination (sam+线段树合并)
- 【GDOI2017模拟一试4.11】腐女的生日(线段树+维护一次函数)
- 【GDOI2017模拟9.10】子串
- 51Nod 算法马拉松17 Simple KMP 链剖维护SAM的fail树
- CF 671D Roads in Yusland 线段树维护代价合并的思想
- AC自动机 fail树 线段树维护
- CF 338E Optimize! (线段树)
- CF 338E Optimize! (线段树)
- JZOJ4479【GDOI2016模拟4.26】游戏 线段树维护多条线段的信息
- 4774. 【GDOI2017模拟9.10】子串
- CF 558E 线段树
- CF 671D Roads in Yusland 线段树维护代价合并的思想 ★ ★ ★ ★
- 【GDOI2017模拟】树的难题
- cf-edu#6-E - New Year Tree -dfs序+线段树维护
- CF 6E 线段树 or Multiset or 双端队列维护区间最值
- JZOJ4417 【HNOI2016模拟4.1】神奇的字符串 线段树维护信息
- CF 23E(Tree-树-背包合并)
- PHP 取得刚插入数据的ID
- 第七周项目2-友元类(1)
- Storm基本概念
- 数组顺序移动
- 第七周项目2-友元类(2)
- JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
- C++ operator关键字(重载操作符)
- Struts2_05_ActionMethod动态方法调用_DMI
- shell脚本执行出错时处理
- 第七周项目3-用多文件组织多个类的程序
- 聚类算法评价指标
- poj 1190 生日蛋糕(dfs 剪枝)
- location.href的用户总结
- Android编程日记