洛谷P4008 [NOI2003] 文本编辑器 题解 块状链表

题目链接:https://www.luogu.com.cn/problem/P4008

思路和题解参考自:https://www.luogu.com.cn/article/jsj8kne5

Find 函数很好用!赞!

区别:

  • 我是自己手写的双向链表;
  • 由于我的操作不会出现大于 blo(blo 是设定的最大分块大小)的分块,所以不会出现块大小 大于 blo 的情况,所以 Update 函数中不会切分块(只需合并块)

另外,要 注意一些细节

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5, blo = 2500;

int T, l[maxn], r[maxn], idx, pos;
vector<char> vec[maxn];
char op[15];

void ins(int x, int y) {
    int z = r[x];
    r[x] = y, l[y] = x;
    r[y] = z, l[z] = y;
}

int Find(int &pos) {
    for (int x = 0; ; x = r[x]) {
        if (pos <= vec[x].size())
            return x;
        pos -= vec[x].size();
    }
    assert(1 == 0);
}

void Split(int x, int k) {
    assert(k <= vec[x].size());
    if (k == vec[x].size())
        return;
    int y = ++idx;
    vec[y].assign(vec[x].begin() + k, vec[x].end());
    vec[x].erase(vec[x].begin() + k, vec[x].end());
    ins(x, y);
}

void Update() {
    for (int x = r[0]; x; x = r[x]) {
        int y = r[x];
        if (y && vec[x].size() + vec[y].size() <= blo) {
            int z = r[y];
            vec[x].insert(vec[x].end(), vec[y].begin(), vec[y].end());
            vec[y].clear();
            r[x] = z, l[z] = x;
        }
    }
}

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%s", op);
        if (op[0] == 'M') {  // Move k
            scanf("%d", &pos);
        }
        else if (op[0] == 'I') { // Insert n s
            int n, p = pos; char c;
            scanf("%d", &n);
            int x = Find(p);
            Split(x, p);

            int y = ++idx;
            int sz = 0;
            while (n--) {
                c = getchar();
                while (c < 32 || c > 126)
                    c = getchar();
                vec[y].push_back(c);
                if (++sz == blo && n) {
                    ins(x, y);
                    x = r[x];       /** 这句话也很重要! **/
                    assert(x == y);
                    y = ++idx;
                    sz = 0;
                }
            }
            if (sz)
                ins(x, y);

            Update();
        }
        else if (op[0] == 'D') { // Delete n
            int n;
            scanf("%d", &n);
            int p1 = pos, p2 = pos + n;
            int x = Find(p1), y = Find(p2);
            Split(y, p2);       /*****************************/
            int z = r[y];       /** 注意这三行的顺序!!! **/
            Split(x, p1);       /*****************************/
            r[x] = z, l[z] = x;
            Update();
        }
        else if (op[0] == 'G') { // Get n
            int n;
            scanf("%d", &n);
            int p1 = pos, p2 = pos + n;
            int x = Find(p1), y = Find(p2);
            for (int i = x; ; i = r[i]) {
                int a = 0, b = vec[i].size();
                if (i == x) a = p1;
                if (i == y) b = p2;
                for (int j = a; j < b; j++)
                    putchar(vec[i][j]);
                if (i == y)
                    break;
            }
            putchar('\n');
        }
        else if (op[0] == 'P') { // Prev
            pos--;
        }
        else {  // Next
            pos++;
        }
    }
    return 0;
}
posted @ 2026-03-06 11:31  quanjun  阅读(2)  评论(0)    收藏  举报