CF418E Tricky Password

发布时间 2023-09-15 08:47:56作者: Ender_32k

1Da 2y。

不难发现发现 \(a_2=a_4=a_6=\cdots\)\(a_3=a_5=a_7=\cdots\),于是只需要维护前 \(3\) 行的值即可。

不难发现 \(a_{2,x}\)\(a_{1,x}\) 在前缀中出现的次数,\(a_{3,x}\)\(a_{1,x}\) 前缀中至少出现了 \(x\) 次的数的个数。

不难发现分块即可。

不难发现分块只需要维护 \(O(\sqrt n)\) 个块内 \(O(n)\) 个值,分别表示对于每种权值,在块的前缀中的出现次数。查询时继承 \(y\) 所在的块的前一个块的答案,然后剩下的一段后缀暴力跑即可。

// Problem: Tricky Password
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF418E
// Memory Limit: 500 MB
// Time Limit: 3500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

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

namespace vbzIO {
    char ibuf[(1 << 20) + 1], *iS, *iT;
    #if ONLINE_JUDGE
    #define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
    #else
    #define gh() getchar()
    #endif
    #define mt make_tuple
    #define mp make_pair
    #define fi first
    #define se second
    #define pc putchar
    #define pb emplace_back
    #define ins insert
    #define era erase
    typedef tuple<int, int, int> tu3;
    typedef pair<int, int> pi;
    inline int rd() {
        char ch = gh();
        int x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void wr(int x) {
        if (x < 0) x = ~(x - 1), putchar('-');
        if (x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace vbzIO;

const int N = 1e5 + 100;
const int B = 350;

int n, m, b, len, a[N], t[N << 1];
int lp[B], rp[B], pos[N], c[B][N << 1], s[B][N];

struct qr {
	int op, x, y;
	qr () { }
	qr (int _op, int _x, int _y) : op(_op), x(_x), y(_y) { }
} q[N];

void add(int x, int y) { c[x][y]++, s[x][c[x][y]]++; }
void del(int x, int y) { s[x][c[x][y]]--, c[x][y]--; }

vector<int> qry(int x) {
	vector<int> res(2);
	for (int i = lp[pos[x]]; i <= x; i++) add(pos[x] - 1, a[i]);
	res[0] = c[pos[x] - 1][a[x]], res[1] = s[pos[x] - 1][res[0]];
	for (int i = lp[pos[x]]; i <= x; i++) del(pos[x] - 1, a[i]);
	return res;
}

int main() {
	n = rd();
	for (int i = 1; i <= n; i++) 
		a[i] = rd(), t[++len] = a[i];
	m = rd();
	for (int i = 1, op, x, y; i <= m; i++) {
		op = rd(), x = rd(), y = rd(), q[i] = qr(op, x, y);
		if (op == 1) t[++len] = x;
	}
	sort(t + 1, t + len + 1), len = unique(t + 1, t + len + 1) - t - 1;
	for (int i = 1; i <= n; i++) a[i] = lower_bound(t + 1, t + len + 1, a[i]) - t;
	for (int i = 1; i <= m; i++)
		if (q[i].op == 1) q[i].x = lower_bound(t + 1, t + len + 1, q[i].x) - t;
	b = sqrt(n);
	for (int i = 1; i <= b; i++)
		lp[i] = (i - 1) * b + 1, rp[i] = i * b;
	if (rp[b] < n) b++, lp[b] = rp[b - 1] + 1, rp[b] = n;
	for (int i = 1; i <= b; i++)
		for (int j = lp[i]; j <= rp[i]; j++) pos[j] = i;
	for (int i = 1; i <= b; i++) {
		memcpy(c[i], c[i - 1], sizeof(int) * (len + 5));
		memcpy(s[i], s[i - 1], sizeof(int) * (n + 5));
		for (int j = lp[i]; j <= rp[i]; j++) add(i, a[j]);
	}
	for (int i = 1; i <= m; i++) {
		int op = q[i].op, x = q[i].x, y = q[i].y;
		if (op == 1) {
			for (int j = pos[y]; j <= b; j++) del(j, a[y]); a[y] = x;
			for (int j = pos[y]; j <= b; j++) add(j, a[y]);
		} else {
			if (x == 1) wr(t[a[y]]), pc('\n');
			else wr(qry(y)[x & 1]), pc('\n');
		}
	}
    return 0;
}