思路:我们先跟着它给定的字符串走把字典树建出来,求出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 ;
} /*
*/

最新文章

  1. JavaScript 省市级联效果
  2. OpenGL FAQ
  3. JS多异步之间的协作方案
  4. Java多线程之Runable与Thread
  5. python 字符串连接
  6. 发现数据库错误模式(AppScan扫描结果)
  7. POJ 2112 Optimal Milking 【网络流】【二分】【最短路】
  8. union 中可以存储的是不带构造函数的类对象
  9. Visual Studio 那些隐藏的调试功能(转)
  10. IOS-连接
  11. C# 获取本机IP地址以及转换字符串
  12. IO库 8.5
  13. WireShark 使用
  14. Android+openCV 动态人脸检测
  15. 大数据Spark与Storm技术选型
  16. HTTP Authentication
  17. 从外部设置传入Go变量
  18. 【转】BAT批处理中的字符串处理详解(字符串截取)
  19. Jacob用法收集
  20. linux下通过curl访问web服务器

热门文章

  1. 跨平台sdk接入总结
  2. uboot两阶段代码分析
  3. sublime text3常用快捷键
  4. [洛谷P3629] [APIO2010]巡逻
  5. elk相关
  6. JNLP Slave connection error解决办法
  7. 【Foreign】Walk [暴力]
  8. 【POJ】2947 Widget Factory(高斯消元)
  9. HDU 1070 Milk (模拟)
  10. 关于auto-keras训练cnn模型