bzoj 2434 AC自动机 + fail指针建树 + 树状数组
2024-09-26 23:49:24
思路:我们先跟着它给定的字符串走把字典树建出来,求出fail指针,我们考虑两个字符串 A和B,
如果想要求B中有多少A的子串,转换一下就是有多少个B的前缀的后缀包含A,这个在AC自动机
的状态图中很容易表示,就是字符串B所占的结点中 有多少个结点顺着fail能到达A的尾结点,
并且fail构建出来的图是一棵树,转换成A的尾结点的子树中有多少个B的节点,用dfs序构建树状
数组能很容易完成,又因为有m组询问,我们把询问离线排序,就能解决问题啦。
#include<bits/stdc++.h>
#define LL long long
#define ll long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define y1 skldjfskldjg
#define y2 skldfjsklejg using namespace std; const int N = 2e5 + ;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = ; int n, m, pos, ans[N], t[N];
char s[N]; struct Qus {
int x, y, id;
bool operator < (const Qus &rhs) const {
return y < rhs.y;
}
} qus[N]; struct BIT {
int a[N];
void modify(int x, int v) {
for(int i = x; i < N; i += i & -i)
a[i] += v;
}
int sum(int x) {
int ans = ;
for(int i = x; i; i -= i & -i)
ans += a[i];
return ans;
}
} bit; struct Ac {
int ch[N][], val[N], dp[N], f[N], L[N], R[N], tot, sz, cnt, all;
bool vis[N];
vector<PII> vec[N];
vector<int> edge[N]; Ac(int sz) {this->sz = sz;}
void init() {tot = ;}
int newNode() {
tot++; f[tot] = ; val[tot] = ;
memset(ch[tot], , sizeof(ch[tot]));
return tot;
}
inline int idx(char c) {return c - 'a';}
void addStr(char *s) {
stack<int> stk;
int u = ;
stk.push();
for(int i = ; s[i]; i++) {
if(s[i] == 'P') {
cnt++; val[u]++; t[cnt] = u;
while(pos <= n && qus[pos].y <= cnt)
vec[u].push_back(mk(qus[pos].x, qus[pos].id)), pos++;
} else if(s[i] == 'B') {
if(stk.size() > ) {
stk.pop();
u = stk.top();
}
} else {
int c = idx(s[i]);
if(!ch[u][c]) ch[u][c] = newNode();
u = ch[u][c];
stk.push(u);
}
}
} void build() {
queue<int> que;
for(int c = ; c < sz; c++) {
int v = ch[][c];
if(!v) ch[][c] = ;
else f[v] = , que.push(v);
}
while(!que.empty()) {
int u = que.front(); que.pop();
val[u] |= val[f[u]];
for(int c = ; c < sz; c++) {
int v = ch[u][c];
if(!v) ch[u][c] = ch[f[u]][c];
else f[v] = ch[f[u]][c], que.push(v);
}
}
} void dfs(int u) {
L[u] = ++all;
for(int i = ; i < edge[u].size(); i++) {
int v = edge[u][i];
dfs(v);
}
R[u] = all;
} void solve(char *s) {
for(int i = ; i <= tot; i++)
edge[f[i]].push_back(i); dfs(); stack<int> stk;
int u = ;
stk.push();
bit.modify(L[], );
for(int i = ; s[i]; i++) {
if(s[i] == 'P') {
if(vis[u]) continue;
vis[u] = true; for(int i = ; i < vec[u].size(); i++) {
int x = t[vec[u][i].fi], id = vec[u][i].se;
ans[id] = bit.sum(R[x]) - bit.sum(L[x] - );
}
} else if(s[i] == 'B') {
if(stk.size() > ) {
bit.modify(L[u], -);
stk.pop();
u = stk.top();
}
} else {
int c = idx(s[i]);
u = ch[u][c];
stk.push(u);
bit.modify(L[u], );
}
}
for(int i = ; i <= n; i++) printf("%d\n", ans[i]);
}
} ac(); int main() {
ac.init(); pos = ;
scanf("%s%d", s, &n);
for(int i = ; i <= n; i++) {
scanf("%d%d", &qus[i].x, &qus[i].y);
qus[i].id = i;
}
sort(qus + , qus + + n);
ac.addStr(s);
ac.build();
ac.solve(s);
return ;
} /*
*/
最新文章
- JavaScript 省市级联效果
- OpenGL FAQ
- JS多异步之间的协作方案
- Java多线程之Runable与Thread
- python 字符串连接
- 发现数据库错误模式(AppScan扫描结果)
- POJ 2112 Optimal Milking 【网络流】【二分】【最短路】
- union 中可以存储的是不带构造函数的类对象
- Visual Studio 那些隐藏的调试功能(转)
- IOS-连接
- C# 获取本机IP地址以及转换字符串
- IO库 8.5
- WireShark 使用
- Android+openCV 动态人脸检测
- 大数据Spark与Storm技术选型
- HTTP Authentication
- 从外部设置传入Go变量
- 【转】BAT批处理中的字符串处理详解(字符串截取)
- Jacob用法收集
- linux下通过curl访问web服务器