询问离线,按照y分类,构建出Fail树,询问(x,y)等价于询问,有多少个Trie树上从y到根节点的路径上经过的点,出现在Fail树上x的子树内。
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using int_t = long long int;
using std::cin;
using std::cout;
using std::endl;
const int_t LARGE = 1e5;
int_t vtxID;
struct Node {
Node* trieChd[26];
Node* link = nullptr;
Node* parent = nullptr;
int_t id;
std::vector<int_t> strID;
Node*& access(char chr) { return trieChd[chr - 'a']; }
Node() {
id = ++vtxID;
memset(trieChd, 0, sizeof(trieChd));
}
};
std::vector<int_t> failTree[LARGE + 1];
int_t arr[LARGE + 1];
Node* root = new Node();
Node* strs[LARGE + 1];
int_t DFSN[LARGE + 1];
int_t result[LARGE + 1];
int_t size[LARGE + 1];
int_t m;
struct Query {
int_t y, x;
int_t id;
};
std::vector<Query> querys[LARGE + 1];
void DFS(int_t vtx) {
DFSN[vtx] = ++DFSN[0];
size[vtx] = 1;
for (int_t to : failTree[vtx]) {
DFS(to);
size[vtx] += size[to];
}
}
int_t lowbit(int_t x) { return x & (-x); }
void add(int_t pos, int_t val) {
while (pos <= vtxID) {
arr[pos] += val;
pos += lowbit(pos);
}
}
int_t query(int_t pos) {
int_t result = 0;
while (pos >= 1) {
result += arr[pos];
pos -= lowbit(pos);
}
return result;
}
int_t query(int_t left, int_t right) { return query(right) - query(left - 1); }
void DFS2(Node* node) {
add(DFSN[node->id], 1);
if (node->strID.empty() == false) {
for (int_t id : node->strID) {
for (const auto& query : querys[id]) {
result[query.id] = ::query(
DFSN[strs[query.x]->id],
DFSN[strs[query.x]->id] - 1 + size[strs[query.x]->id]);
}
}
}
for (char chr = 'a'; chr <= 'z'; chr++) {
if (node->access(chr)) {
Node* to = node->access(chr);
DFS2(to);
}
}
add(DFSN[node->id], -1);
}
int main() {
#ifdef DEBUG
freopen("qwq.txt", "r", stdin);
#endif
static char buf[LARGE + 10];
int_t used = 0;
scanf("%s", buf);
Node* node = root;
for (char* ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr == 'B') {
node = node->parent;
#ifdef DEBUG
cout << "back to " << node->id << endl;
#endif
} else if (*ptr == 'P') {
node->strID.push_back(++used);
strs[used] = node;
#ifdef DEBUG
cout << "print at " << node->id << " strid = " << used << endl;
#endif
} else {
if (node->access(*ptr) == nullptr) {
Node*& next = node->access(*ptr);
next = new Node;
next->parent = node;
}
node = node->access(*ptr);
#ifdef DEBUG
cout << "walk with " << *ptr << " to " << node->id << endl;
#endif
}
}
std::queue<Node*> queue;
for (char chr = 'a'; chr <= 'z'; chr++)
if (root->access(chr)) {
root->access(chr)->link = root;
queue.push(root->access(chr));
failTree[root->id].push_back(root->access(chr)->id);
}
while (queue.empty() == false) {
Node* front = queue.front();
queue.pop();
for (char chr = 'a'; chr <= 'z'; chr++) {
if (front->access(chr)) {
Node*& link = front->access(chr)->link;
Node* curr = front->link;
while (curr && curr->access(chr) == nullptr) curr = curr->link;
if (curr == nullptr)
link = root;
else
link = curr->access(chr);
failTree[link->id].push_back(front->access(chr)->id);
#ifdef DEBUG
cout << "fail " << front->access(chr)->id << " = " << link->id
<< endl;
#endif
queue.push(front->access(chr));
}
}
}
DFS(1);
scanf("%lld", &m);
for (int_t i = 1; i <= m; i++) {
int_t x, y;
scanf("%lld%lld", &x, &y);
querys[y].push_back(Query{y, x, i});
}
DFS2(root);
for (int_t i = 1; i <= m; i++) {
printf("%d\n", (int)result[i]);
}
return 0;
}