---
# System prepended metadata

title: suffix trie
tags: [codebook]

---

---
tags: codebook
---

{%hackmd theme-dark %}

# suffix trie
```cpp=
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
constexpr size_t cAlphaSize = 128;
struct suffix_trie {
	struct node {
		size_t start, end, index;
		node *slink;
		vector<node*> next;
	}*root, *needslink, *active_node;
	string data;
	size_t remainder, active_index, active_length;
	size_t length(node* x) {
		return min(x->end, data.size()) - x->start;
	}
	node* newnode(size_t a, size_t b = string::npos, size_t c = 0) {
		node* x = new node;
		x->start = a, x->end = b;
		x->index = c ? c : data.size() - remainder;
		x->next.assign(cAlphaSize, x->slink = root);
		return x;
	}
	size_t active_edge() {return data[active_index];}
	void addslink(node* x) {
		if (needslink != root)
			needslink->slink = x;
		needslink = x;
	}
	bool walk_down(node* x) {
		if (active_length < length(x))
			return false;
		active_index += length(x);
		active_length -= length(x);
		active_node = x;
		return true;
	}
	void init() {
		active_node = needslink = root = newnode(string::npos, string::npos);
		active_index = active_length = remainder = 0;
		root->next.assign(cAlphaSize, root->slink = root);
	}
	void extend(char c) {
		data.push_back(c);
		needslink = root, remainder++;
		while (remainder > 0) {
			if (!active_length)
				active_index = data.size() - 1;
			if (active_node->next[active_edge()] == root)
				active_node->next[active_edge()] = newnode(data.size() - 1), addslink(active_node);
			else {
				node* nxt = active_node->next[active_edge()];
				if (walk_down(nxt)) continue;
				if (data[nxt->start + active_length] == c) {
					active_length++;
					addslink(active_node);
					break;
				}
				node* split = newnode(nxt->start, nxt->start + active_length, string::npos);
				active_node->next[active_edge()] = split;
				split->next[size_t(c)] = newnode(data.size() - 1);
				nxt->start += active_length;
				split->next[size_t(data[nxt->start])] = nxt;
				addslink(split);
			}
			remainder--;
			if (active_node == root && active_length)
				active_length--, active_index = data.size() - remainder;
			else
				active_node = active_node->slink;
		}
	}
	void dfs(node* cur, vector<size_t>& v) {
		if (cur == root) return;
		if (cur->index != string::npos)
			v.push_back(cur->index);
		for (size_t i = 0; i != cAlphaSize; i++)
			dfs(cur->next[i], v);
	}
	vector<size_t> search(const string& str) {
		vector<size_t> v;
		node* cur = root->next[str.front()];
		size_t i = 0, j = 0;
		while (cur != root && i < str.size()) {
			if (j >= length(cur))
				cur = cur->next[str[i]], j = 0;
			if (str[i] != data[cur->start + j])
				return v;
			i++, j++;
		}
		if (cur != root)
			dfs(cur, v);
		return v;
	}
	bool count(const string& str) {
		node* cur = root->next[str.front()];
		size_t i = 0, j = 0;
		while (cur != root && i < str.size()) {
			if (j >= length(cur))
				cur = cur->next[str[i]], j = 0;
			if (str[i] != data[cur->start + j])
				return false;
			i++, j++;
		}
		return cur != root;
	}
	suffix_trie(const string & str) {
		init();
		for (const auto& i : str)
			extend(i);
		extend('\0');
	}
};
ostream& operator<<(ostream& os, const vector<auto>& v) {
	for (const auto& i : v)
		os << i << ' ';
	return os;
}
int main() {
	string a, b;
	while (cin >> a >> b)
		cout << vector<string> {"No", "Yes"} [suffix_trie(b).count(a)] << endl;
	return 0;
}
```