【BZOJ3879】SvT

这篇博客是对BZOJ3879题目的补档,提供了问题的解析思路,但并未给出详细题解。博客主要内容围绕题目本身展开,探讨了解题的关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目链接】

【思路要点】

  • 补档博客,无题解。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	1000005
#define MAXM	3000005
#define MAXLOG	22
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
int n, m, a[MAXM];
char s[MAXN];
struct Suffix_Automaton {
	int depth[MAXN], home[MAXN];
	int father[MAXN][MAXLOG];
	int child[MAXN][26];
	vector <int> a[MAXN], b[MAXN];
	int size, root, last, timer;
	int dfn[MAXN], dep[MAXN];
	int index[MAXN], Len;
	long long cnt[MAXN];
	long long ans, now;
	int new_node(int dep) {
		depth[size] = dep;
		return size++;
	}
	void Extend(int ch) {
		int p = last, np = new_node(depth[p] + 1);
		while (child[p][ch] == 0) {
			child[p][ch] = np;
			p = father[p][0];
		}
		if (child[p][ch] == np) father[np][0] = root;
		else {
			int q = child[p][ch];
			if (depth[p] + 1 == depth[q]) father[np][0] = q;
			else {
				int nq = new_node(depth[p] + 1);
				father[nq][0] = father[q][0];
				father[np][0] = father[q][0] = nq;
				memcpy(child[nq], child[q], sizeof(child[q]));
				while (child[p][ch] == q) {
					child[p][ch] = nq;
					p = father[p][0];
				}
			}
		}
		last = np;
	}
	void dfs(int pos) {
		dfn[pos] = ++timer;
		for (unsigned i = 0; i < a[pos].size(); i++) {
			dep[a[pos][i]] = dep[pos] + 1;
			dfs(a[pos][i]);
		}
	}
	void init(int len, char *s) {
		Len = len;
		size = timer = 0;
		root = last = new_node(0);
		for (int i = 1; i <= len; i++) {
			Extend(s[i] - 'a');
			home[i] = last;
		}
		for (int i = 1; i < size; i++)
			a[father[i][0]].push_back(i);
		for (int p = 1; p < MAXLOG; p++)
		for (int i = 1; i < size; i++)
			father[i][p] = father[father[i][p - 1]][p - 1];
		dfs(0);
	}
	int Lca(int x, int y) {
		if (dep[x] < dep[y]) swap(x, y);
		for (int p = MAXLOG - 1; p >= 0; p--)
			if (dep[father[x][p]] >= dep[y]) x = father[x][p];
		if (x == y) return x;
		for (int p = MAXLOG - 1; p >= 0; p--)
			if (father[x][p] != father[y][p]) {
				x = father[x][p];
				y = father[y][p];
			}
		return father[x][0];
	}
	void getcnt(int pos) {
		cnt[pos] = index[pos];
		for (unsigned i = 0; i < b[pos].size(); i++) {
			getcnt(b[pos][i]);
			cnt[pos] += cnt[b[pos][i]];
		}
	}
	void work(int root) {
		now += cnt[root] * depth[root];
		if (index[root]) ans += now;
		for (unsigned i = 0; i < b[root].size(); i++) {
			now -= cnt[b[root][i]] * depth[root];
			work(b[root][i]);
			now += cnt[b[root][i]] * depth[root];
		}
		now -= cnt[root] * depth[root];
	}
	long long query(int n, int *pos) {
		static int Stack[MAXN], Queue[MAXN];
		int top = 0, tot = 0;
		Stack[++top] = Queue[++tot] = root;
		for (int i = 1; i <= n; i++) {
			int now = pos[i];
			index[now] = 1;
			int lca = Lca(now, Stack[top]);
			if (lca == Stack[top]) Stack[++top] = Queue[++tot] = now;
			else {
				while (dfn[lca] < dfn[Stack[top - 1]]) {
					b[Stack[top - 1]].push_back(Stack[top]);
					top--;
				}
				if (lca == Stack[top - 1]) {
					b[lca].push_back(Stack[top--]);
					Stack[++top] = Queue[++tot] = now;
				} else {
					b[lca].push_back(Stack[top--]);
					Stack[++top] = Queue[++tot] = lca;
					Stack[++top] = Queue[++tot] = now;
				}
			}
		}
		for (int i = 1; i < top; i++)
			b[Stack[i]].push_back(Stack[i + 1]);
		ans = now = 0;
		getcnt(root);
		work(root);
		for (int i = 1; i <= tot; i++) {
			int tmp = Queue[i];
			ans -= index[tmp] * depth[tmp];
			index[tmp] = cnt[tmp] = 0;
			b[tmp].clear();
		}
		return ans / 2;
	}
} SAM;
bool cmp(int x, int y) {
	return SAM.dfn[x] < SAM.dfn[y];
}
int main() {
	read(n), read(m);
	scanf("\n%s", s + 1);
	reverse(s + 1, s + n + 1);
	SAM.init(n, s);
	for (int i = 1; i <= m; i++) {
		int x; read(x);
		for (int j = 1; j <= x; j++)
			read(a[j]), a[j] = SAM.home[n - a[j] + 1];
		sort(a + 1, a + x + 1, cmp);
		x = unique(a + 1, a + x + 1) - (a + 1);
		printf("%lld\n", SAM.query(x, a));
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值