社区讨论

求问

P13981数列分块入门 6参与者 1已保存回复 1

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
1 条
当前快照
1 份
快照标识符
@mlnycvro
此快照首次捕获于
2026/02/16 00:21
4 天前
此快照最后确认于
2026/02/16 21:56
3 天前
查看原帖
我的做法大概是对于块长 BB,每 BB 个元素用一个链表维护,然后使用一个新的链表维护这 nB\frac{n}{B} 个链表。
查询时,在大链表上顺序遍历,找到需要查询的元素在哪个小链表里,然后暴力进去查找即可。
修改时,找到对应的小链表,然后直接插进去即可。
不过要注意,当一个小链表长度超过 2B2B 时,就要拆成两个新的小链表,然后插到大链表中。
然后呢,我按照这个要求写了一份代码,在洛谷上直接过了:
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
bool ST;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void pc(char ch){putchar(ch);}
inline void write(int x){
    if(x < 0) pc('-'), x = -x;
    if(x > 9) write(x / 10);
    pc(x % 10 + '0');
    return;
}
const int B = 548; // 一杯茶,一包烟,一个块长调一天
struct LinkedList{
    int len = 0, a[(B << 1) + 5], nxt[(B << 1) + 5], pre[(B << 1) + 5], lst;
    inline void clear(){
        len = lst = 0;
        memset(a, 0, sizeof(a));
        memset(nxt, 0, sizeof(nxt));
        memset(pre, 0, sizeof(pre)); // memset 吧,反正不是复杂度瓶颈
        return;
    }
    inline int getid(int x){
        int p = 0;
        while(x--) p = nxt[p];
        return p;
    }
    inline void append(int k){
        a[++len] = k;
        nxt[lst] = len;
        pre[len] = lst;
        lst = len;
        return;
    }
    inline void insert(int x, int k){
        x = getid(x);
        a[++len] = k;
        nxt[pre[x]] = len;
        pre[len] = pre[x], nxt[len] = x;
        pre[x] = len;
        return;
    }
    inline int query(int x){
        int u = 0;
        while(x--) u = nxt[u];
        return a[u];
    }
}xlb[(B << 1) + 5], dlb; // 小链表,大链表
int n, a[300005], len;
inline void init(){
    int i = 1;
    while(i <= n){
        len++;
        while(xlb[len].len <= B){
            xlb[len].append(a[i++]);
        }
        dlb.append(len);
    }
    return;
}
inline void modify(int x, int k){
    int xid = 1;
    while(xlb[xid].len < x) x -= xlb[xid].len, xid++;
    xlb[xid].insert(x, k);
    if(xlb[xid].len >= (B << 1)){
        vector<int> v;
        int p = xlb[xid].nxt[0];
        while(p) v.push_back(p), p = xlb[xid].nxt[p];
        xlb[xid].clear();
        for(int i = 0; i < B; i++) xlb[xid].append(v[i]);
        len++;
        for(int i = B; i < (int)v.size(); i++) xlb[len].append(v[i]);
        dlb.insert(dlb.nxt[xid], len);
    }
    return;
}
inline int query(int x){
    int xid = 1;
    while(xlb[xid].len < x) x -= xlb[xid].len, xid++;
    return xlb[xid].query(x);
}
bool ED;
signed main(){
    n = read();
    for(int i = 1; i <= n; i++) a[i] = read();
    init();
    int q = n;
    while(q--){
        int op = read();
        if(op == 0){
            int l = read(), r = read();
            modify(l, r);
        }else{
            int x = read();
            write(query(x)), pc('\n');
        }
    }
    cerr << 1.0 * abs(&ED - &ST) / 1024 / 1024 << " MB" << '\n';
    return 0;
}
然后改了输入格式交到 loj 上,全 WA。
我尝试修改了块长,然后发现 BB 越大,对的行数就越多。
求问原因 qwq

回复

1 条回复,欢迎继续交流。

正在加载回复...