题解 CF666E Forensic Examination
题意
给定一个长度为
数据范围:
题解
对
然后建立 parent tree,在上面跑一个线段树合并,合并的方式只能是新建节点,直接在原树上合并会改变其他子节点的结构。
类似求 LCS,处理出
每次查询,先判没有匹配的情况,即
认为
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10, Log = 20, S = 26;
struct node {
int mx, cnt;
node(int Mx = 0, int Cnt = 0) { mx = Mx, cnt = Cnt; }
friend bool operator < (const node &qwq, const node &awa) {
return qwq.cnt == awa.cnt ? qwq.mx > awa.mx : qwq.cnt < awa.cnt;
}
friend node operator + (const node &qwq, const node &awa) {
return node(qwq.mx, qwq.cnt + awa.cnt);
}
};
struct edge {
int to, nxt;
} e[N << 1];
int head[N], ecnt;
void add(int u, int v) {
e[++ecnt] = (edge){v, head[u]};
head[u] = ecnt;
}
int n, m, q;
int fa[Log][N], dep[N], pos[N], maxl[N];
char s[N], t[N];
namespace SegmentTree {
int rt[N], ls[N * Log], rs[N * Log], tot;
node v[N * Log];
void pushup(int x) { v[x] = max(v[ls[x]], v[rs[x]]); }
void insert(int &x, int l, int r, int p) {
if(!x) x = ++tot;
if(l == r) {
v[x].cnt++;
v[x].mx = l;
return;
}
int mid = l + r >> 1;
if(p <= mid) insert(ls[x], l, mid, p);
else insert(rs[x], mid + 1, r, p);
pushup(x);
}
int merge(int a, int b, int l, int r) {
if(!a || !b) return a + b;
int x = ++tot;
if(l == r) {
v[x] = v[a] + v[b];
return x;
}
int mid = l + r >> 1;
ls[x] = merge(ls[a], ls[b], l, mid);
rs[x] = merge(rs[a], rs[b], mid + 1, r);
pushup(x);
return x;
}
node query(int x, int l, int r, int L, int R) {
if(!x) return node();
if(L <= l && r <= R) return v[x];
node res;
int mid = l + r >> 1;
if(mid >= L) res = max(res, query(ls[x], l, mid, L, R));
if(mid < R) res = max(res, query(rs[x], mid + 1, r, L, R));
return res;
}
} using namespace SegmentTree;
namespace SAM {
struct state {
int len, link, ch[S];
} st[N];
int last, cnt = 1;
void insert(int c, int i) {
int p = last, q, x = ++cnt, y;
st[x].len = st[p].len + 1;
SegmentTree::insert(rt[x], 1, m, i);
for(; p && !st[p].ch[c]; p = st[p].link) st[p].ch[c] = x;
if(!p) st[x].link = 1;
else {
q = st[p].ch[c];
if(st[q].len == st[p].len + 1) st[x].link = q;
else {
st[y = ++cnt] = st[q];
st[y].len = st[p].len + 1;
st[q].link = st[x].link = y;
for(; p && st[p].ch[c] == q; p = st[p].link) st[p].ch[c] = y;
}
}
last = x;
}
void insert(char *t, int k) {
int len = strlen(t + 1);
for(int i = 1; i <= len; i++)
insert(t[i] - 'a', k);
}
} using namespace SAM;
void dfs(int u) {
for(int i = head[u], v; i; i = e[i].nxt) {
v = e[i].to;
fa[0][v] = u;
dfs(v);
rt[u] = merge(rt[u], rt[v], 1, m);
}
}
int main() {
scanf("%s%d", s + 1, &m);
n = strlen(s + 1);
for(int i = 1; i <= m; i++) {
scanf("%s", t + 1);
last = 1, insert(t, i);
}
for(int i = 2; i <= cnt; i++)
add(st[i].link, i);
dfs(1);
for(int i = 1; i < Log; i++)
for(int j = 1; j <= cnt; j++)
fa[i][j] = fa[i - 1][fa[i - 1][j]];
for(int i = 1, c, p = 1, l = 0; i <= n; i++) {
c = s[i] - 'a';
if(st[p].ch[c]) p = st[p].ch[c], l++;
else {
for(; p && !st[p].ch[c]; p = st[p].link);
if(!p) p = 1, l = 0;
else l = st[p].len + 1, p = st[p].ch[c];
}
pos[i] = p, maxl[i] = l;
}
scanf("%d", &q);
while(q--) {
int l, r, pl, pr, len;
scanf("%d%d%d%d", &l, &r, &pl, &pr), len = pr - pl + 1;
if(len > maxl[pr]) { printf("%d 0\n", l); continue; }
int u = pos[pr];
for(int i = Log - 1; ~i; i--)
if(st[fa[i][u]].len >= len)
u = fa[i][u];
node ans = query(rt[u], 1, m, l, r);
if(!ans.cnt) ans.mx = l;
printf("%d %d\n", ans.mx, ans.cnt);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话