T609147 数列编辑器(editor)
解题思路
这道题目要求实现一个数列编辑器,支持插入、删除、光标移动和查询操作。关键在于需要高效处理动态变化的数列,并能够快速查询任意区间的前缀和最大值。
方法选择
题目提供的代码使用了双栈+线段树的解法:
-
双栈模型:
-
ls栈存储光标左侧的元素 -
rs栈存储光标右侧的元素 -
通过栈操作实现光标的移动和插入删除
-
-
线段树:
-
维护前缀和数组
s的最大值 -
支持单点更新和区间最大值查询
-
每次操作后更新线段树
-
操作分析
-
插入(I x):将x压入
ls栈,更新前缀和数组和线段树 -
删除(D):弹出
ls栈顶,重置线段树对应位置 -
左移(L):将
ls栈顶移到rs栈,更新线段树 -
右移(R):将
rs栈顶移到ls栈,更新前缀和和线段树 -
查询(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; }

浙公网安备 33010602011771号