CF1286E Fedya the Potter Strikes Back

Posted by chandan_tiwari on Sun, 07 Nov 2021 00:37:35 +0100

\(\Large\texttt{CF1286E Fedya the Potter Strikes Back }\)

It is expected that the theoretical complexity is \ (\ mathcal O(n\alpha(n)) \) and theoretically the table calculation is suspended, but it seems that it is actually not better than the submission of some \ (\ mathcal O(n\log n) \).

thinking

For the answer that we need to maintain dynamically, first classify all contributing intervals \ ([L, R] \) and make them the contribution of points \ (R \). It is found that it is difficult to directly calculate the contribution of points \ (i \) every time, and consider inheriting the contribution of \ (i - 1 \).

In order to facilitate understanding, the concept of suffix tree is introduced here.

For points \ (i - 1 \) and \ (i \), their depth on the suffix tree must meet \ (dep_{i} \le dep_{i - 1} + 1 \), that is, adding one character at a time will only increase one border at most, and its length is \ (1 \).

Then we consider how to inherit the contribution of \ (i - 1 \) to \ (I \). All points from the point \ (I \) on the suffix tree to the root node must be inherited from all points from the point \ (i - 1 \) on the suffix tree to the root node (except for the border with the length of \ (1 \). That is, we classify all left end points in the interval \ ([L, i] \) in which the point \ (I \) contributes as a set \ (s_, I \), Then \ (S_i \in S_{i - 1} \cup \{i \} \), so we just delete all unsatisfied \ (L \) by force and inherit them directly in \ (S_{i - 1} \), and the maximum total number of deletions is \ (\ mathcal O(n) \).

We use the monotone stack to maintain the \ (w_i \) with increasing suffix, because only these elements contribute. In this process, we insert all the current \ (L \in S_i \) into the position that belongs to its contribution \ (w_i \). For inserting new elements \ (w_i \), if it is necessary to merge and delete the top elements of the stack, we can use and query to point them to \ (I \), That is, move the element originally contributed to the top of the stack to \ (I \).

For the deletion operation, it is similar to other problem solutions. Maintain an ancestor where the first subsequent character on the suffix tree is different from its own subsequent character. Just jump and delete it violently.

code

#include <bits/stdc++.h>
using namespace std;

#define PB push_back
// #define int long long
#define LL long long
#define siz(a) ((int)((a).size()))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
const int N = 6e5;
const int M = 100000;
const int mod = 1e9 + 7;
const int inf = 1e9;

int a, nxt[N + 5], w[N + 5], fa[N + 5], top, siz[N + 5], sk[N + 5], lst[N + 5], sz[N + 5];
__int128 ans, tmp;
char s[N + 5];

int f(int n) {
	return fa[n] == n ? n : fa[n] = f(fa[n]);
}

void merge(int &p1, int &p2) {
	tmp -= 1ll * w[p2] * siz[p2];
	tmp += 1ll * w[p1] * siz[p2];
	if(sz[p1] < sz[p2]) swap(p1, p2);
	w[p1] = min(w[p1], w[p2]);
	fa[p2] = p1;
	siz[p1] += siz[p2];
	sz[p1] += sz[p2];
}
void out(__int128 x){
	static int buf[255], len;
	if(!x) return cout << "0\n", void();
	while(x) buf[++len] = x % 10, x /= 10;
	while(len) cout << (char) (buf[len--] + '0');
	cout << "\n";
}

signed main() {
	// freopen("in1.in", "r", stdin);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> a;
	int j = 0, mx = (1ll << 30) - 1;
	rep(i, 1, a) {
		cin >> s[i] >> w[i];
		w[i] = (w[i] ^ (ans & mx));
		s[i] = (ans + s[i] - 'a') % 26 + 'a';
		sk[++top] = i;
		fa[i] = i;
		sz[i] = 1;
		while(top > 1 && w[sk[top]] <= w[sk[top - 1]]) {
			swap(sk[top], sk[top - 1]);
			merge(sk[top - 1], sk[top]);
			--top;
		}
		if(i > 1) {
			lst[i - 1] = ((s[i] == s[j + 1]) ? lst[j] : j);
			for(; j && s[j + 1] != s[i]; j = nxt[j]) {
				--siz[f(i - j)];
				tmp -= w[f(i - j)];
			}
			for(int k = lst[j]; k; ) {
				if(s[k + 1] == s[i]) {
					k = lst[k];
					continue;
				}
				--siz[f(i - k)];
				tmp -= w[f(i - k)];
				k = nxt[k];
			}
			if(s[j + 1] == s[i]) ++j;
			nxt[i] = j;
			if(s[1] == s[i]) {
				++siz[f(i)];
				tmp += w[f(i)];
			}
		}
		ans += tmp + w[f(sk[1])];
		out(ans);
	}
	return 0;
}

Topics: Union Find