• 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) << "
    ";
    	}
    }
    
  • 相关阅读:
    [转]学习B站动态转发抽奖脚本
    【LeetCode】236. 二叉树的最近公共祖先
    Java中邮件的发送
    最长递增子序列(LIS)
    最长公共子序列(LCS)
    【LeetCode】69. x 的平方根
    Lombok的使用
    Centos 中文乱码解决方法
    FWT,FST入门
    [UOJ310][UNR #2]黎明前的巧克力
  • 原文地址:https://www.cnblogs.com/lieberdq/p/13641831.html
Copyright © 2020-2023  润新知