Cod sursa(job #1560407)

Utilizator howsiweiHow Si Wei howsiwei Data 2 ianuarie 2016 17:40:12
Problema Aho-Corasick Scor 30
Compilator cpp Status done
Runda Arhiva educationala Marime 4.34 kb
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

class SufA {
public:
	const string s;
	const int n;
	vector<int> sa;
	vector<int> elcp;
public:
	SufA(const string& _s) : s(_s), n(s.size()) {
	}
	template <typename T>
	void sais(const int n, const T& s, const int nc) {
		const int nil = -1;
		fill(begin(sa), begin(sa)+n, nil);
		vector<bool> t(n);
		t[n-1] = true;
		for (int i = n-2; i >= 0; i--) {
			t[i] = s[i] < s[i+1]
				|| s[i] == s[i+1] && t[i+1];
		}
		auto isLMS = [&t] (int i) {
			return t[i] &&  i >= 1 && !t[i-1];
		};
		vector<int> bkt(nc+1);
		for (int i = 0; i < n; i++) {
			bkt[s[i]+1]++;
		}
		partial_sum(begin(bkt), end(bkt), begin(bkt));
		auto bkt1 = bkt;
		for (int i = n-1; i >= 1; i--) {
			if (isLMS(i)) {
				sa[--bkt1[s[i]+1]] = i;
			}
		}
		auto induceSAl = [&] (vector<int> bkt) {
			for (int i = 0; i < n-1; i++) {
				int j = sa[i]-1;
				if (j >= 0 && !t[j]) {
					sa[bkt[s[j]]++] = j;
				}
			}
		};
		auto induceSAs = [&] (vector<int> bkt) {
			for (int i = n-1; i >= 2; i--) {
				int j = sa[i]-1;
				if (j >= 0 && t[j]) {
					sa[--bkt[s[j]+1]] = j;
				}
			}
		};
		induceSAl(bkt);
		induceSAs(bkt);
		int n1 = 0;
		for (int i = 0; i < n; i++) {
			if (isLMS(sa[i])) {
				sa[n1++] = sa[i];
			}
		}
		int ord = 0;
		for (int i = 0; i < n1; i++) {
			if (i >= 1) {
				ord++;
				for (int j = 0; s[sa[i-1]+j] == s[sa[i]+j]; j++) {
					if (isLMS(sa[i]+j) && j >= 1) {
						if (isLMS(sa[i-1]+j)) ord--;
						break;
					}
				}
			}
			sa[n1+sa[i]/2] = ~ord;
		}
		if (ord+1 < n1) {
			int* s1 = &sa[0]+n1;
			for (int i = n1, j = 0; j < n1; i++) {
				if (sa[i] < 0) {
					s1[j++] = ~sa[i];
				}
			}
			sais(n1, s1, ord+1);
			for (int i = 1, j = 0; i < n; i++) {
				if (isLMS(i)) {
					s1[j++] = i;
				}
			}
			for (int i = 0; i < n1; i++) {
				sa[i] = s1[sa[i]];
			}
		}
		fill(begin(sa)+n1, begin(sa)+n, nil);
		bkt1 = bkt;
		for (int i = n1-1; i >= 0; i--) {
			int j = sa[i];
			sa[i] = nil;
			sa[--bkt1[s[j]+1]] = j;
		}
		induceSAl(bkt);
		induceSAs(bkt);
	}
	void buildsa() {
		sa.resize(n);
		if (n >= 2) sais(n, s, 128);
		// for (int i = 0; i < n; i++) {
		// 	printf("%d%c", sa[i], " \n"[i == n-1]);
		// }
	}
	void buildelcp() {
		vector<int> ra(n);
		for (int i = 0; i < n; i++) {
			ra[sa[i]] = i;
		}
		elcp.resize(2*n);
		// elcp[2*n-1] = -1;
		for (int j = 0, len = 0; j < n-1; j++) {
			int i = sa[ra[j]-1];
			while (s[i+len] == s[j+len]) len++;
			elcp[n+ra[i]] = len;
			len = max(len-1, 0);
		}
		for (int i = n-1; i >= 1; i--) {
			elcp[i] = min(elcp[2*i], elcp[2*i+1]);
		}
		// int x = n;
		// while (x % 2 == 0) x /= 2;
		// x /= 2;
		// while (x != 0) {
		// 	elcp[x] = -1;
		// 	x /= 2;
		// }
		// for (int i = 0; i < 2*n; i++) {
		// 	printf("%d%c", elcp[i], " \n"[i == 2*n-1]);
		// }
	}
	pair<int,int> range(const string& t) {
		int l = n;
		int i = n>>__builtin_ctz(n);
		int cp = 0;
		bool lr = false;
		while (l+l/i >= 2*n) {
			i <<= 1;
		}
		while (i <= l) {
			bool next;
			if (elcp[i+lr] != cp) {
				next = lr == elcp[i+lr] < cp;
			} else {
				int k = sa[l-n+l/i];
				while (cp < t.size() && t[cp] == s[k+cp]) cp++;
				if (cp == t.size()) {
					l = l+l/i;
					i++;
					i <<= 1;
					break;
				}
				next = s[k+cp] < t[cp];
				lr = !next;
			}
			if (next) {
				l += l/i;
				i++;
				if (i&1) {
					i <<= 1;
				} else {
					i >>= __builtin_ctz(i);
					while (l+l/i >= 2*n) {
						i <<= 1;
					}
				}
			} else {
				i <<= 1;
			}
		}
		if (cp < t.size()) {
			int k = l-n+1;
			return {k, k};
		}
		int r = l;
		while (i <= l) {
			if (elcp[i-1] < t.size()) {
				i <<= 1;
			} else {
				l -= l/i;
				i--;
				i <<= 1;
			}
		}
		l -= n;
		i = r>>__builtin_ctz(r);
		while (r+r/i >= 2*n) {
			i <<= 1;
		}
		while (i <= r) {
			if (elcp[i] < t.size()) {
				i <<= 1;
			} else {
				r += r/i;
				i++;
				if (i&1) {
					i <<= 1;
				} else {
					i >>= __builtin_ctz(i);
					while (r+r/i >= 2*n) {
						i <<= 1;
					}
				}
			}
		}
		r -= n-1;
		return {l, r};
	}
};

int main() {
	ios::sync_with_stdio(false);
	freopen("ahocorasick.in", "r", stdin);
	freopen("ahocorasick.out", "w", stdout);
	string s;
	cin >> s;
	SufA suf(s+'\0');
	suf.buildsa();
	suf.buildelcp();
	int nq;
	cin >> nq;
	for (int iq = 0; iq < nq; iq++) {
		string t;
		cin >> t;
		auto res = suf.range(t);
		// printf("%d %d\n", res.first, res.second);
		printf("%d\n", res.second-res.first);
	}
}