LibreOJ #6282

题目链接:#6282. 数列分块入门 6

题目大意

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及单点插入,单点询问

solution

我们对于这两种操作:

修改操作: 我们计入一下每个块的大小,然后找到所在的快, 每找到一个整块直接减去这个块的大小即可,然后当不能减了,就是所在块,直接暴力插入即可

查询操作: 同修改操作,找到所在块,然后直接输出

然后,我们喜闻乐见的 超时了

我们发现如果一直插入一个块里,这个块会变得非常大,我们就会超时

我们有两种应对措施:

  1. 我们可以每多 \(\sqrt(n)\) 的时候,进行暴力重构

  2. 我们也可以在某个块达到一定大小时,暴力重构

暴力重构的时间复杂度是正确的,自己可以证明一下本人不想写了

Code:

/**
*    Author: Alieme
*    Data: 2020.9.8
*    Problem: LibreOJ #6282
*    Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>

#define ll long long
#define rr register

#define inf 1e9
#define MAXN 200010

using namespace std;

inline void read(int &T) {
	T = 0;
	int f = 0;
	char ch = getchar();
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) T = T * 10 + (ch ^ 48), ch = getchar();
	if (f) T = -T;
}

void print(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + 48);
}

int n, len, sum, tot;

int siz[MAXN], id[MAXN], a[MAXN];

int v[600][MAXN];

inline void build() {
	sum = 0;
	int cnt = 0;
	for (rr int i = 1; i <= id[tot]; i++) 
		for (rr int j = 1; j <= siz[i]; j++)
			a[++cnt] = v[i][j];
	tot = cnt;
	memset(siz, 0, sizeof siz);
	for (rr int i = 1; i <= tot; i++) 
		id[i] = (i - 1) / len + 1, v[id[i]][++siz[id[i]]] = a[i];
}

inline void add(int l, int r) {
	int i;
	sum++;
	for (i = 1; i <= id[tot]; i++) 
		if (l - siz[i] > 0) l -= siz[i]; 
		else break;
	for (rr int k = siz[i] + 1; k >= l; k--) v[i][k + 1] = v[i][k];
	v[i][l] = r;
	siz[i]++;
	if (sum == len) build();
}

inline int query(int r) {
	int i;
	for (i = 1; i <= id[tot]; i++)
		if (r - siz[i] > 0) r -= siz[i];
		else break;
	return v[i][r];
}

signed main() {
	// freopen("a1.in", "r", stdin);
	// freopen("a.out", "w", stdout);
	read(n);
	len = sqrt(n);
	for (rr int i = 1; i <= n; i++) read(a[i]), id[i] = (i - 1) / len + 1, v[id[i]][++siz[id[i]]] = a[i];
	tot = n;
	for (rr int i = 1; i <= n; i++) {
		int opt, l, r, c;
		read(opt), read(l), read(r), read(c);
		if (opt == 0) add(l, r);
		if (opt == 1) cout << query(r) << "\n";
	}
}
posted @ 2020-09-09 21:02  Aliemo  阅读(113)  评论(0编辑  收藏  举报