LOJ 6041 事情的相似度 题解

Statement

先把串 reverse,多次给 \(l,r\),求

\[ \max_{l\le i<j\le r}\{\text{LCP}(i,j)\} \]

Solution

  • \(\text{sqrtlog}\sim\text{sqrt}\):莫队 + 线段树 / 树状数组 / set,用 SA 做
  • \(nm/\omega\):bitset 乱搞
  • \(\log^2\):SAM + LCT + BIT

在 parent 树上,LCP 等于 LCA 的 len

离线,每次加入右端点就 access 一下,过程中对产生的 LCA 关系进行更新.

  • 还有一种做法是在 parent 树上 set 启发式合并,然后二维数点

Code

一遍写完一遍过!太牛了。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 2e5 + 10;
vector<pair<int, int>> Queries[N];
int n, m;
string s;

struct BIT {
	int len, mx[N];
	BIT(int _len = 0) {
		len = _len, memset(mx, 0, sizeof(mx));
	}
	void Upd(int x, int v) {
		for (; x <= len; x += x & -x) mx[x] = max(mx[x], v);
	}
	int Qry(int x) {
		int res = 0;
		for (; x; x -= x & -x) res = max(res, mx[x]);
		return res;
	}
} bit;

namespace SAM {
	int sz, cur, last, len[N], link[N], nxt[N][2];
	void init() {
		link[0] = -1;
	}
	void extend(int ch) {
		cur = ++sz, len[cur] = len[last] + 1;
		int p = last;
		for (; ~p; p = link[p])
			if (!nxt[p][ch]) nxt[p][ch] = cur;
			else break;
		if (!~p) {
			link[cur] = 0;
		} else {
			int q = nxt[p][ch];
			if (len[p] + 1 == len[q]) {
				link[cur] = q;
			} else {
				int copy = ++sz;
				link[copy] = link[q], link[q] = link[cur] = copy, len[copy] = len[p] + 1;
				nxt[copy][0] = nxt[q][0], nxt[copy][1] = nxt[q][1];
				for (; ~p; p = link[p])
					if (nxt[p][ch] == q) nxt[p][ch] = copy;
					else break;
			}
		}
		last = cur;
	}
	void Build() {
		init();
		for (auto ch : s) extend(ch - 48);
		bit = BIT(n);
	}
}

int now;

namespace LinkCutTree {
	int fa[N], ch[N][2], tag[N], val[N];
  #define get(u) (u == ch[fa[u]][1])
  #define nrt(u) (u == ch[fa[u]][0] || u == ch[fa[u]][1])
	void cov(int u, int v) {
		if (u) tag[u] = val[u] = v;
	}
	void down(int u) {
		if (tag[u]) cov(ch[u][0], tag[u]), cov(ch[u][1], tag[u]), tag[u] = 0;
	}
	void Down(int u) {
		if (nrt(u)) Down(fa[u]);
		down(u);
	}
	void rot(int u) {
		int f = fa[u], g = fa[f], k = get(u);
		if (nrt(f)) ch[g][get(f)] = u;
		ch[f][k] = ch[u][!k];
		if (ch[u][!k]) fa[ch[u][!k]] = f;
		ch[u][!k] = f, fa[f] = u, fa[u] = g;
	}
	void splay(int u) {
		for (Down(u); nrt(u); rot(u)) if (nrt(fa[u])) rot(get(u) == get(fa[u]) ? fa[u] : u);
	}
	void access(int u) {
		int v = 0;
		for (; u; v = u, u = fa[u]) {
			splay(u);
			if (v) {
				bit.Upd(n - val[u] + 1, SAM::len[u - 1]);
			}
			ch[u][1] = v;
		}
		cov(v, now);
	}
  #undef get
  #undef nrt
}
int ans[N];

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr);
	cin >> n >> m >> s;
	rep(i, 1, m) {
		int l, r;
		cin >> l >> r;
		Queries[r].push_back(make_pair(l, i));
	}
	SAM::Build();
	rep(i, 1, SAM::sz) LinkCutTree::fa[i + 1] = SAM::link[i] + 1;
	int pos = 0;
	rep(i, 1, n) {
		now = i;
		pos = SAM::nxt[pos][s[i - 1] - 48];
		LinkCutTree::access(pos + 1);
		for (auto qry : Queries[i])
			ans[qry.second] = bit.Qry(n - qry.first + 1);
	}
	rep(i, 1, m) {
		cout << ans[i] << '\n';
	}
	return 0;
}

posted @ 2024-10-07 09:14  Laijinyi  阅读(4)  评论(0编辑  收藏  举报