uoj395

题意

给串 \(s\)
\(q\) 次询问,每次给串 \(t\)\(l,\ r\) 问有多少个不同字符串 \(r\) 满足 \(r\)\(t\) 的子串且 \(r\) 不为 \(s[l...r]\) 的子串。

\(1\ \leq\ |s|\ \leq\ 5\ *\ 10^5,\ 1\ \leq\ q\ \leq\ 10^5,\ 1\ \leq\ \sum\ |T|\ \leq\ 10^6\)

做法1

每次询问对于 \(i\) 只要求出最大的 \(len\) 使得 \(t[i...i\ +\ len_i\ -\ 1]\)\(s[l...r]\) 中出现或 \(t[i\ +\ 1...]\) 中出现即可。可以发现 \(len_i\ \leq\ len_{i\ +\ 1}\ +\ 1\),所以从后往前扫,每次暴力求 \(len\) 即可。用个 \(SA\) 维护,时间复杂度 \(O(n\ log\ n)\)
注意 \(ST\) 表询问时预处理 \(2\) 的次幂常数较小。
uoj 评测鸡好不稳定啊,这份代码大概会在 76 到 96 分之间随机。qaq

代码

#include <bits/stdc++.h>

#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif

using namespace std;

struct fast_io {
	static const int istream_size = (1 << 22) | 10, ostream_size = (1 << 21) | 10;

	char istream[istream_size], ostream[ostream_size], *i, *o;

	fast_io() { fread(istream, 1, istream_size, stdin); i = istream; o = ostream; }
	~fast_io() { fwrite(ostream, 1, o - ostream, stdout); }

	void read(char *s, int &n) {
		while(*i < 'a') ++i;
		n = 0;
		while(*i >= 'a') s[n++] = *i++;
		return;
	}

	void read(int &x) {
		while(*i < '0') ++i;
		x = 0;
		while(*i >= '0') x = x * 10 + *i++ - '0';
		return;
	}

	void print(long long &x) {
		if(!x) { *o++ = '0'; *o++ = '\n'; return; }
		static char s[20], *i;
		i = s;
		while(x) {
			long long y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != s) *o++ = *--i;
		*o++ = '\n';
		return;
	}
} io;

struct query {
	int beg, End, l, r, id;

	query() {}
	query(int beg, int End, int l, int r, int id): beg(beg), End(End), l(l), r(r), id(id) {}
};

struct segment_tree {
	static const int oo = 1e9;

	int n, N;
	vector<int> num;

	segment_tree() {}
	segment_tree(int _n) { // [1, _n]
		n = _n;
		N = 1; while(N - 1 <= _n) N <<= 1;
		num = vector<int>(N << 1, oo);
	}

	inline void M(int i, const int &x) { for (i |= N; i; i >>= 1) num[i] = min(num[i], x); return; }

	inline int Q(int s, int t) {
		int ret = oo;
		for (s = (s | N) - 1, t = (t | N) + 1; s ^ t ^ 1; s >>= 1, t >>= 1) {
			if(~s & 1) ret = min(ret, num[s ^ 1]);
			if(t & 1) ret = min(ret, num[t ^ 1]);
		}
		return ret;
	}
};

const int maxn = 2e6 + 10;

char s[maxn]; int s_size;

int main() {
	io.read(s, s_size);
	int End = s_size;
	int q; io.read(q);
	vector<query> qry(q); vector<long long> ans(q, 0);
	for (int i = 0; i < q; ++i) {
		s[s_size++] = '#'; int beg = s_size;
		int t_size; io.read(s + s_size, t_size); s_size += t_size;
		int l, r; io.read(l); io.read(r);
		qry[i] = query(beg, s_size - 1, l - 1, r - 1, i);
	}
	sort(qry.begin(), qry.end(), [&](query a, query b) { return a.l > b.l; });
	int n = s_size;
	segment_tree seg(n);
	vector<int> lim(n + 1, 0);

	vector<int> sa(n + 1), rnk(n + 1), LOG(n + 1, 0);
	for (int i = 2; i <= n; ++i) LOG[i] = LOG[i >> 1] + 1;
	vector<vector<int> > h(LOG[n] + 1, vector<int>(n + 1, 0));
	vector<int> pw2(LOG[n] + 1);
	for (int i = 0; i < pw2.size(); ++i) pw2[i] = 1 << i;

	function<void(vector<int> &)> pre_sum = [&](vector<int> &v) {
		for (int i = 1; i < v.size(); ++i) v[i] += v[i - 1];
		return;
	};

	function<void()> build_SA = [&]() {
		vector<int> cnt(max(n + 3, 300), 0);
		vector<pair<pair<int, int>, int> > p(n), q(n);
		for (int i = 0; i < n; ++i) cnt[s[i]] = 1;
		pre_sum(cnt);
		int mx = cnt.back();
		for (int i = 0; i < n; ++i) rnk[i] = cnt[s[i]];
		for (int len = 1; mx < n; len <<= 1) {
			fill(cnt.begin(), cnt.end(), 0);
			for (int i = 0; i < n; ++i) {
				p[i] = make_pair(make_pair(rnk[i], (i + len < n ? rnk[i + len] : 0)), i);
				++cnt[p[i].first.second + 1];
			}
			pre_sum(cnt);
			for (int i = 0; i < n; ++i) q[cnt[p[i].first.second]++] = p[i];
			fill(cnt.begin(), cnt.end(), 0);
			for (int i = 0; i < n; ++i) ++cnt[q[i].first.first + 1];
			pre_sum(cnt);
			for (int i = 0; i < n; ++i) p[cnt[q[i].first.first]++] = q[i];
			mx = 0;
			for (int i = 0; i < n; ++i) {
				if(!i || p[i].first != p[i - 1].first) ++mx;
				rnk[p[i].second] = mx;
			}
		}
		rnk[n] = 0;
		for (int i = 0; i <= n; ++i) sa[rnk[i]] = i;
		for (int k = 0, i = 0; i < n; ++i) {
			if(k) --k;
			int j = sa[rnk[i] - 1];
			while(i + k < n && j + k < n && s[i + k] == s[j + k]) ++k;
			h[0][rnk[i]] = k;
		}
		for (int lg = 1; lg < h.size(); ++lg) {
			int len = 1 << lg - 1;
			for (int i = 1; i + len <= n; ++i) h[lg][i] = min(h[lg - 1][i], h[lg - 1][i + len]);
		}
		return;
	};

	auto hQ = [&](const int &l, const int &r) {
		int lg = LOG[r - l + 1];
		return min(h[lg][l], h[lg][r - pw2[lg] + 1]);
	};

	auto lcp = [&](int i, int j) {
		i = rnk[i]; j = rnk[j];
		return hQ(min(i, j) + 1, max(i, j));
	};

	auto find_lb = [&](const int &rnk_i, const int &len, const int &lst) {
		int lb = 1, rb = lst - 1;
		while(lb <= rb) {
			int mid = lb + rb >> 1;
			if(hQ(mid + 1, rnk_i) >= len) rb = mid - 1;
			else lb = mid + 1;
		}
		return lb;
	};

	auto find_rb = [&](const int &rnk_i, const int &len, const int &lst) {
		int lb = lst + 1, rb = n;
		while(lb <= rb) {
			int mid = lb + rb >> 1;
			if(hQ(rnk_i + 1, mid) >= len) lb = mid + 1;
			else rb = mid - 1;
		}
		return rb;
	};

	build_SA();

	for (int i = End - 1, j = 0; ~i && j < q; --i) {
		seg.M(rnk[i], i);
		while(j < q && qry[j].l == i) {
			vector<int> pos;
			for (int k = qry[j].beg; k <= qry[j].End; ++k) pos.push_back(k);
			sort(pos.begin(), pos.end(), [&](int i, int j) { return rnk[i] < rnk[j]; });
			vector<int> stk;
			for (int i: pos) {
				while(stk.size() && stk.back() < i) stk.pop_back();
				if(stk.size()) lim[i] = max(lim[i], lcp(i, stk.back()));
				stk.push_back(i);
			}
			reverse(pos.begin(), pos.end()); stk.clear();
			for (int i: pos) {
				while(stk.size() && stk.back() < i) stk.pop_back();
				if(stk.size()) lim[i] = max(lim[i], lcp(i, stk.back()));
				stk.push_back(i);
			}
			int len = 0;
			for (int k = qry[j].End; k >= qry[j].beg; --k) {
				++len;
				int lst_lb, lst_rb; lst_lb = lst_rb = rnk[k];
				while(len > 0) {
					int lb = find_lb(rnk[k], len, lst_lb), rb = find_rb(rnk[k], len, lst_rb);
					if(seg.Q(lst_lb = lb, lst_rb = rb) + len - 1 <= qry[j].r) break;
					--len;
				}
				ans[qry[j].id] += (qry[j].End - k + 1 - max(len, lim[k]));
			}
			++j;
		}
	}

	for (auto t: ans) io.print(t);
	return 0;
}
posted @ 2018-10-12 11:54  King_George  阅读(124)  评论(0编辑  收藏  举报