T609147 数列编辑器(editor)

解题思路

这道题目要求实现一个数列编辑器,支持插入、删除、光标移动和查询操作。关键在于需要高效处理动态变化的数列,并能够快速查询任意区间的前缀和最大值。

方法选择

题目提供的代码使用了双栈+线段树的解法:

  1. 双栈模型

    • ls栈存储光标左侧的元素

    • rs栈存储光标右侧的元素

    • 通过栈操作实现光标的移动和插入删除

  2. 线段树

    • 维护前缀和数组s的最大值

    • 支持单点更新和区间最大值查询

    • 每次操作后更新线段树

操作分析

  1. 插入(I x):将x压入ls栈,更新前缀和数组和线段树

  2. 删除(D):弹出ls栈顶,重置线段树对应位置

  3. 左移(L):将ls栈顶移到rs栈,更新线段树

  4. 右移(R):将rs栈顶移到ls栈,更新前缀和和线段树

  5. 查询(Q l r):使用线段树查询区间[l,r]的最大前缀和

代码注释

#include<bits/stdc++.h>
#define ll long long
#define lc rt << 1      // 左子节点索引
#define rc rt << 1 | 1  // 右子节点索引
#define lson lc,l,mid   // 左子树参数
#define rson rc,mid + 1,r // 右子树参数
using namespace std;

const int N = 2e5 + 10, inf = 0x3f3f3f3f;

// 线段树节点结构体
struct node{
    int sum;  // 存储区间最大值(实际是前缀和的最大值)
};

node t[N << 2];  // 线段树数组
int q;           // 操作次数
int ls[N], rs[N]; // 双栈:ls-光标左侧,rs-光标右侧
int top1, top2;   // 栈顶指针
int s[N];         // 前缀和数组

// 更新父节点的最大值
void pushup(int rt)
{
    t[rt].sum = max(t[lc].sum, t[rc].sum);
}

// 构建线段树(初始时所有位置为0)
void build(int rt, int l, int r)
{
    if(l == r){
        t[rt].sum = s[l];  // 初始前缀和为0
        return;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt);
}

// 单点更新函数
void change(int rt, int l, int r, int x, int num)
{
    if(r < x || x < l) return;  // 超出范围
    if(l == r){
        t[rt].sum = num;  // 更新前缀和
        return;
    }
    int mid = (l + r) >> 1;
    change(lson, x, num);
    change(rson, x, num);
    pushup(rt);
}

// 区间查询最大值
int query(int rt, int l, int r, int x, int y)
{
    if(r < x || y < l) return -inf;  // 无交集返回极小值
    if(x <= l && r <= y) return t[rt].sum;  // 完全包含直接返回
    int mid = (l + r) >> 1;
    return max(query(lson, x, y), query(rson, x, y));  // 返回左右子树的最大值
}

int main()
{
    build(1, 1, N - 1);  // 初始化线段树
    
    cin >> q;
    while(q--)
    {
        char op; cin >> op;
        
        if(op == 'I'){  // 插入操作
            int x; cin >> x;
            ls[++top1] = x;  // 压入左栈
            s[top1] = s[top1 - 1] + x;  // 更新前缀和
            change(1, 1, N - 1, top1, s[top1]);  // 更新线段树
        }
        
        if(op == 'D'){  // 删除操作
            change(1, 1, N - 1, top1, 0);  // 重置该位置
            top1--;  // 弹出左栈顶
        }
        
        if(op == 'L'){  // 光标左移
            if(top1 > 0){
                rs[++top2] = ls[top1];  // 左栈顶移到右栈
                change(1, 1, N - 1, top1, 0);  // 重置原位置
                top1--;  // 左栈指针减1
            }
        }
        
        if(op == 'R'){  // 光标右移
            if(top2 > 0){
                ls[++top1] = rs[top2];  // 右栈顶移到左栈
                s[top1] = s[top1 - 1] + rs[top2];  // 更新前缀和
                top2--;  // 右栈指针减1
                change(1, 1, N - 1, top1, s[top1]);  // 更新线段树
            }
        }
        
        if(op == 'Q'){  // 查询操作
            int x, y; scanf("%d%d", &x, &y);
            printf("%d\n", query(1, 1, N - 1, x, y));  // 查询区间最大前缀和
        }
    }
    return 0;
}

 

posted @ 2025-05-21 10:08  CRt0729  阅读(10)  评论(0)    收藏  举报