Luogu P6864 [RC-03] 記憶

rizynvu發表於2024-07-01

先考慮沒有 \(3\) 操作該怎麼做。
對於當前字串把其分成多組互不包含的括號的形式,即 \((\cdots)()()\) 這樣,考慮經過 \(1 / 2\) 操作後對互不包含的括號組數 \(b\) 和答案 \(v\) 會產生什麼影響。

  • \(1\) 操作,加上過後便會多上一組互不包含的括號,\(b\leftarrow b' + 1\),同時這個括號能和前面的所有互不包含的括號連起來對答案產生貢獻,\(v\leftarrow v' + b' + 1\)
  • \(2\) 操作,此時所有括號都被新的括號包含了,\(b = 1\),答案會多上整個串,\(v\leftarrow v' + 1\)

再來考慮有 \(3\) 操作該怎麼做,這個操作即可以改變一個操作對答案是否產生貢獻,每次進行此操作都需要重頭再推,考慮降低修改的時間複雜度。
單點修改全域性查詢,考慮到使用線段樹,再結合 \(v, b\) 能發現其變化都是 \(\times +\) 操作,考慮把其寫成矩陣的形式 \(\begin{bmatrix}v & b & 1\end{bmatrix}\),再來考慮構造每個操作對應的矩陣。

  • \(1\) 操作:\(\begin{bmatrix}v & b & 1\end{bmatrix} \times\begin{bmatrix}1 & 0 & 0 \\ 1 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix}= \begin{bmatrix}v + b + 1 & b + 1 & 1\end{bmatrix}\)
  • \(2\) 操作:\(\begin{bmatrix}v & b & 1\end{bmatrix} \times\begin{bmatrix}1 & 0 & 0 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{bmatrix}= \begin{bmatrix}v + 1 & 1 & 1\end{bmatrix}\)
  • \(3\) 操作:如果是被刪除的操作還原按照 \(1 / 2\) 操作構造即可,若是刪除則為單位矩陣,即 \(\begin{bmatrix}v & b & 1\end{bmatrix} \times\begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}= \begin{bmatrix}v & b & 1\end{bmatrix}\)

對於每個操作,直接單點修改對應位置的矩陣即可,最後用初始矩陣 \(\begin{bmatrix}1 & 1 & 1\end{bmatrix}\) 乘上全部的操作矩陣的乘積即可。

時間複雜度 \(\mathcal{O}(w^3\times n\log n)\)\(w\) 為矩陣大小。

#include<bits/stdc++.h>
using ll = long long;
const int N = 2e5 + 10;
int n;
struct Matrix {
	ll a[3][3];
	Matrix() {
		memset(a, 0, sizeof(a));
	}
	const ll* operator [] (int x) const {
		return a[x];
	}
	ll* operator [] (int x) {
		return a[x];
	}
	Matrix operator * (const Matrix &b) const {
		Matrix c;
		for (int i = 0; i < 3; i++) {
			for (int k = 0; k < 3; k++) {
				for (int j = 0; j < 3; j++) {
					c[i][j] += a[i][k] * b[k][j];
				}
			}
		}
		return c;
	}
	Matrix operator *= (const Matrix &b) {
		return *this = *this * b;
	}
};
Matrix t[N * 4];
void pushup(int k) {
	t[k] = t[k << 1] * t[k << 1 | 1];
}
void build(int k = 1, int l = 1, int r = n) {
	if (l == r) {
		t[k][0][0] = t[k][1][1] = t[k][2][2] = 1;
		return ;
	}
	int mid = (l + r) >> 1;
	build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
	pushup(k);
}
void update(int x, const Matrix &y, int k = 1, int l = 1, int r = n) {
	if (l == r) {
		t[k] = y;
		return ;
	}
	int mid = (l + r) >> 1;
	if (x <= mid) {
		update(x, y, k << 1, l, mid);
	} else {
		update(x, y, k << 1 | 1, mid + 1, r);
	}
	pushup(k);
}
int opt[N], x[N], vis[N];
void make_matrix(int opt, Matrix &z) {
	if (opt == 0) {
		z[0][0] = z[1][1] = z[2][2] = 1;
	} else if (opt == 1) {
		z[0][0] = z[1][0] = z[1][1] = z[2][0] = z[2][1] = z[2][2] = 1;
	} else if (opt == 2) {
		z[0][0] = z[2][0] = z[2][1] = z[2][2] = 1;
	}
}
int main() {
	scanf("%d", &n);
	build();
	for (int i = 1; i <= n; i++) {
		scanf("%d", &opt[i]);
		if (opt[i] != 3) {
			Matrix z;
			make_matrix(opt[i], z);
			update(i, z);
		} else if (opt[i] == 2) {
			Matrix z;
			z[0][0] = z[2][0] = z[2][1] = z[2][2] = 1;
			update(i, z);
		} else {
			scanf("%d", &x[i]);
			if (opt[x[i]] == 3) {
				x[i] = x[x[i]];
			}
			vis[x[i]] ^= 1;
			Matrix z;
			make_matrix(vis[x[i]] ? 0 : opt[x[i]], z);
			update(x[i], z);
		}
		Matrix x;
		x[0][0] = x[0][1] = x[0][2] = 1;
		x *= t[1];
		printf("%lld\n", x[0][0]);
	}
	return 0;
}

相關文章