Description

传送门

Solution

对 \(T[1..m]\) 建立广义后缀自动机,离线,找出代表 \(S[pl,pr]\) 的每个节点,线段树合并。

Code

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm> const int N = 500005, M = 9500005;
struct Edge {
int v, nxt;
} e[N];
struct Node {
int l, r, x, y, id;
bool operator < (const Node & rhs) const {
return y < rhs.y;
}
} a[N];
struct Pair {
int x, y;
bool operator < (const Pair & rhs) const {
return (x == rhs.x && y > rhs.y) || x < rhs.x;
}
} sum[M], ans[N];
int L[N], q, n, m, mx[N], ch[N][30], sz = 1, las = 1, head[N], tot, fa[N], cnt, ls[M], rs[M], f[20][N], rt[N];
char s[N], t[N];
std::vector<int> b[N]; int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x;
}
void adde(int u, int v) {
e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v;
}
void ins(int c) {
int p = las, np = ++sz;
mx[np] = mx[p] + 1, las = np;
for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if (!p) { fa[np] = 1; return; }
int q = ch[p][c];
if (mx[p] + 1 == mx[q]) { fa[np] = q; return; }
int nq = ++sz;
mx[nq] = mx[p] + 1, fa[nq] = fa[q], fa[np] = fa[q] = nq;
memcpy(ch[nq], ch[q], sizeof ch[q]);
for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}
void update(int &x, int l, int r, int p) {
if (!x) x = ++cnt;
if (l == r) { sum[x].x = 1, sum[x].y = l; return; }
int mid = (l + r) >> 1;
if (p <= mid) update(ls[x], l, mid, p);
else update(rs[x], mid + 1, r, p);
sum[x] = std::max(sum[ls[x]], sum[rs[x]]);
}
Pair query(int x, int l, int r, int L, int R) {
Pair res; res.x = 0, res.y = 0;
if (!x) return res;
if (L <= l && r <= R) return sum[x];
int mid = (l + r) >> 1;
if (L <= mid) res = query(ls[x], l, mid, L, R);
if (mid < R) res = std::max(res, query(rs[x], mid + 1, r, L, R));
return res;
}
int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
if (!ls[x] && !rs[x] && !ls[y] && !rs[y]) { sum[x].x += sum[y].x; return x; }
ls[x] = merge(ls[x], ls[y]);
rs[x] = merge(rs[x], rs[y]);
sum[x] = std::max(sum[ls[x]], sum[rs[x]]);
return x;
}
void dfs1(int u) {
f[0][u] = fa[u];
for (int i = 1; i <= 18; ++i) f[i][u] = f[i - 1][f[i - 1][u]];
for (int i = head[u]; i; i = e[i].nxt) dfs1(e[i].v);
}
void jump(int x, int k) {
for (int i = 18; ~i; --i)
if (mx[f[i][x]] >= a[k].y - a[k].x + 1) x = f[i][x];
b[x].push_back(k);
}
void dfs2() {
int x = 1, y = 0;
for (int i = 1, j = 1; i <= n; ++i) {
int c = s[i - 1] - 'a';
while (x && !ch[x][c]) x = fa[x], y = mx[x];
if (!x) { x = 1, y = 0; continue; }
++y, x = ch[x][c];
while (j <= q && a[j].y < i) ++j;
while (j <= q && a[j].y == i) {
if (y >= a[j].y - a[j].x + 1) jump(x, j);
++j;
}
}
}
void dfs3(int u) {
for (int i = head[u]; i; i = e[i].nxt)
dfs3(e[i].v), rt[u] = merge(rt[u], rt[e[i].v]);
int sz = b[u].size();
for (int i = 0; i < sz; ++i) ans[a[b[u][i]].id] = query(rt[u], 1, m, a[b[u][i]].l, a[b[u][i]].r);
}
int main() {
scanf("%s", s), m = read();
for (int i = 1; i <= m; ++i) {
scanf("%s", t), n = strlen(t), las = 1;
for (int j = 0; j < n; ++j)
ins(t[j] - 'a'), update(rt[las], 1, m, i);
}
q = read(), n = strlen(s);
for (int i = 1; i <= q; ++i) L[i] = a[i].l = read(), a[i].r = read(), a[i].x = read(), a[i].y = read(), a[i].id = i;
std::sort(a + 1, a + q + 1);
for (int i = 2; i <= sz; ++i) adde(fa[i], i);
dfs1(1), dfs2(), dfs3(1);
for (int i = 1; i <= q; ++i) printf("%d %d\n", ans[i].y ? ans[i].y : L[i], ans[i].x);
return 0;
}

[CF 666E] Forensic Examination的更多相关文章

  1. CF 666E Forensic Examination 【SAM 倍增 线段树合并】

    CF 666E Forensic Examination 题意: 给出一个串\(s\)和\(n\)个串\(t_i\),\(q\)次询问,每次询问串\(s\)的子串\(s[p_l:p_r]\)在串\(t ...

  2. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  3. Codeforces 666E Forensic Examination SAM or SA+线段树合并

    E. Forensic Examination http://codeforces.com/problemset/problem/666/E 题目大意:给模式串S以及m个特殊串,q个询问,询问S的子串 ...

  4. Codeforces 666E Forensic Examination

    题意:给定主串s和m个模式串,每次询问[l,r]的模式串中出现s[pl...pr]次数最多的串和次数. 这题挺简单的,先把所有模式串拿来建广义后缀自动机,询问相当于子树众数,用线段树合并即可. 那我为 ...

  5. Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)

    题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...

  6. Codeforces 666E Forensic Examination SAM+权值线段树

    第一次做这种$SAM$带权值线段树合并的题 然而$zjq$神犇看完题一顿狂码就做出来了 $Orz$ 首先把所有串当成一个串建$SAM$ 我们对$SAM$上每个点 建一棵权值线段树 每个叶子节点表示一个 ...

  7. codeforces 666E. Forensic Examination(广义后缀自动机,Parent树,线段树合并)

    传送门: 解题思路: 很坑的一道题,需要离线处理,假如只有一组询问,那么就可以直接将endpos集合直接累加输出就好了. 这里就要将询问挂在树节点上,在进行线段树合并时查询就好了. 代码超级容易写挂的 ...

  8. CodeForces - 666E: Forensic Examination (广义SAM 线段树合并)

    题意:给定字符串S,然后M个字符串T.Q次询问,每次给出(L,R,l,r),问S[l,r]在L到R这些T字符串中,在哪个串出现最多,以及次数. 思路:把所有串建立SAM,然后可以通过倍增走到[l,r] ...

  9. Codeforces 666E Forensic Examination(广义后缀自动机+线段树合并)

    将所有串(包括S)放一块建SAM.对于询问,倍增定位出该子串所在节点,然后要查询的就是该子串在区间内的哪个字符串出现最多.可以线段树合并求出该节点在每个字符串中的出现次数. #include<b ...

随机推荐

  1. WCF优雅使用 KnownType标记的方法

    [KnownType("DerivedTypes")] [DataContract] public abstract class TaskBase { // other class ...

  2. WinForm客户端限速下载(C#限速下载)

    最近由于工作需要,需要开发一个能把服务器上的文件批量下载下来本地保存,关键是要实现限速下载,如果全速下载会影响服务器上的带宽流量.本来我最开始的想法是在服务器端开发一个可以从源头就限速下载的Api端口 ...

  3. 一次快速改寫 SQL Server 高效查詢的範例

    最近線上系統突然出現匯出資料超過 10 筆時,查詢逾時的狀況,在仔細查找之後. 發現了問題原因,透過應用端與數據端兩邊同時調整,將查詢的效率提昇了約數百倍以上 首先,原本應用端的商務邏輯為每一分頁筆數 ...

  4. PPT在HTML网页上播放方法

    项目中遇到一个需求:要求PPT在HTML网页上播放,而且要像电脑一样播放PPT,大家能想到的是什么方法? 印象中我好像有在网上见到过PPT模板网站上的PPT可以播放,赶紧百度搜了下发现都是用第三方软件 ...

  5. SAP MM 明明已经扩展供应商到采购组织下,采购订单里还是报错?

    SAP MM 明明已经扩展供应商到采购组织下,采购订单里还是报错? 如下的PO 4400000069,处于HELD状态.ME22N试图保存它为一个正式的采购订单,报错说供应商没有在采购组织下维护, 使 ...

  6. nlp中文分词(jieba和pyltp)

    分词是中文自然语言处理的基础.目前常用的分词算法有 1.张华平博士的NShort中文分词算法. 2.基于条件随机场(CRF)的中文分词算法. 这两种算法的代表工具包分别是jieba分词系统和哈工大的L ...

  7. android - TextView单行显示...或者文字左右滚动(走马灯效果)

    条件 TextView单行显示,文字左右滚动(走马灯效果)实现条件: 实现单行设置固定宽度或者设置权重都行 代码 TextView滚动必须写下面几个属性 android:singleLine=&quo ...

  8. Android远程桌面助手(B1309)

    修改了窗口缩放的处理,支持Android Car等非常规分辨率的Android设备: 修改了获取Android端软件版本的方法,优化了APK的升级逻辑: 优化了远程输入法功能,支持利用PC端输入法快速 ...

  9. Android探究之View的绘制流程

    Android中Activity是作为应用程序的载体存在,代表着一个完整的用户界面,提供了一个窗口来绘制各种视图,当Activity启动时,我们会通过setContentView方法来设置一个内容视图 ...

  10. git常用命令总结--廖雪峰老师Git教程命令总结

    学习了廖雪峰老师的Git教程之后的命令总结,重点关于git和远程仓库的东西. 如果没有学过,这是传送门 下面这个图很重要 一.git初始化本地仓库和配置 echo "想输入到文件的内容,一般 ...