1. 程式人生 > >【LOJ2326】「清華集訓 2017」簡單資料結構

【LOJ2326】「清華集訓 2017」簡單資料結構

【題目連結】

【思路要點】

  • 注意到答案是 O ( L o g M
    ) O(LogM)
    級別的。
  • 對於每一個點 i i 我們暴力維護其 d
    p dp
    d p i dp_i
    以及能夠轉移到 i i 的各個位置的中 d p dp 值為 j j 的位置數 c n t i , j cnt_{i,j}
  • f ( x ) f(x) 表示 x x 的因子個數。
  • 對於操作 0   x 0\ x ,其時間複雜度為 O ( M x + L o g M ) O(\frac{M}{x}+LogM)
  • 對於操作 1   x 1\ x ,其時間複雜度為 O ( i / x f ( i ) + f ( x ) L o g M ) O(\sum_{i/x}f(i)+f(x)*LogM)
  • 對於操作 2 2 ,其時間複雜度為 O ( 1 ) O(1)
  • 對於操作 3 3 ,其時間複雜度為 O ( i / x f ( i ) + f ( x ) L o g M ) O(\sum_{i/x}f(i)+f(x)*LogM)
  • 由於題目保證 C = 10 C=10 ,總時間複雜度是可以接受的。

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXLOG = 25;
const int MAXN = 1e6 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
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;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, m, q, l, r, a[MAXN], ans[MAXLOG];
int pos[MAXN], dp[MAXN], cnt[MAXN][MAXLOG];
void answer() {
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (ans[i]) {
			printf("%d %d\n", i, ans[i]);
			return;
		}
	assert(false);
}
void clear(int x) {
	memset(cnt[x], 0, sizeof(cnt[x]));
	dp[x] = 1, cnt[x][1] = 1;
}
void pushfront(int x) {
	clear(x);
	pos[x] = --l, a[l] = x;
	for (int i = 2 * x; i <= m; i += x)
		if (pos[i]) cnt[x][dp[i] + 1]++;
	for (int i = MAXLOG - 1; i >= 1; i--)
		if (cnt[x][i]) {
			dp[x] = i;
			break;
		}
	ans[dp[x]]++;
}
void popfront() {
	int x = a[l++];
	ans[dp[x]]--, pos[x] = 0;
}
int val[MAXN], old[MAXN], tot;
void update(int x, int val, int d) {
	ans[val] += d;
	for (int i = 1; i * i <= x; i++)
		if (x % i == 0) {
			if (pos[i] < pos[x]) cnt[i][val + 1] += d;
			if (i * i != x && pos[x / i] < pos[x]) cnt[x / i][val + 1] += d;
		}
}
void pushback(int x) {
	clear(x);
	pos[x] = ++r, a[r] = x; tot = 0;
	for (int i = 1; i * i <= x; i++)
		if (x % i == 0) {
			val[++tot] = i, old[i] = dp[i];
			if (i * i != x) val[++tot] = x / i, old[x / i] = dp[x / i];
		}
	sort(val + 1, val + tot + 1);
	update(x, dp[x], 1);
	for (int j = tot - 1; j >= 1; j--) {
		int x = val[j];
		for (int i = MAXLOG - 1; i >= 1; i--)
		if (cnt[x][i]) {
			dp[x] = i;
			break;
		}
		if (!pos[x] || old[x] == dp[x]) continue;
		update(x, old[x], -1);
		update(x, dp[x], 1);
	}
}
void popback() {
	int x = a[r--];
	tot = 0;
	for (int i = 1; i * i <= x; i++)
		if (x % i == 0) {
			val[++tot] = i, old[i] = dp[i];
			if (i * i != x) val[++tot] = x / i, old[x / i] = dp[x / i];
		}
	sort(val + 1, val + tot + 1);
	update(x, dp[x], -1);
	for (int j = tot - 1; j >= 1; j--) {
		int x = val[j];
		for (int i = MAXLOG - 1; i >= 1; i--)
		if (cnt[x][i]) {
			dp[x] = i;
			break;
		}
		if (!pos[x] || old[x] == dp[x]) continue;
		update(x, old[x], -1);
		update(x, dp[x], 1);
	}
	pos[x] = 0;
}
int main() {
	read(n), read(m), read(q);
	l = 5e5, r = l - 1;
	for (int i = 1; i <= n; i++) {
		int x; read(x);
		pushback(x);
	}
	answer();
	for (int i = 1; i <= q; i++) {
		int opt, x; read(opt);
		if (opt <= 1) {
			read(x);
			if (opt == 0) pushfront(x);
			else pushback(x);
		} else {
			if (opt == 2) popfront();
			else popback();
		}
		answer();
	}
	return 0;
}