P8218 【深进1.例1】求区间和 杀鸡焉用宰牛刀
解题思路
这道题目要求我们计算多个区间的和,属于典型的区间查询问题。最直观的解法是对于每个查询直接遍历区间内的元素求和,但这种方法的时间复杂度为O(mn),当n和m较大时(如达到1e5)会超时。
更高效的解法是使用前缀和或线段树:
-
前缀和方法:预处理一个前缀和数组,可以在O(1)时间内回答每个区间查询。
-
线段树方法:构建一个线段树,每个节点存储对应区间的和,可以在O(logn)时间内回答每个区间查询。
虽然前缀和方法更简单高效,但题目提供的代码使用了线段树实现。线段树虽然代码量较大,但它是解决更复杂区间问题(如区间修改、区间最值等)的基础结构。
#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{ ll sum; }; node t[N << 2]; // 线段树数组,大小是原数组的4倍 ll n, m; ll a[N]; // 存储原始数据 // 更新父节点的值(求和) void pushup(int rt) { t[rt].sum = t[lc].sum + t[rc].sum; } // 构建线段树 void build(int rt, int l, int r) { if(l == r){ // 叶子节点,存储单个元素值 t[rt].sum = a[l]; return; } int mid = (l + r) >> 1; // 计算中点 build(lson); // 递归构建左子树 build(rson); // 递归构建右子树 pushup(rt); // 更新当前节点的值 } // 区间查询函数 ll query(int rt, int l, int r, int x, int y) { if(r < x || y < l) return 0; // 当前区间与查询区间无交集 if(x <= l && r <= y) return t[rt].sum; // 当前区间完全包含在查询区间内 int mid = (l + r) / 2; // 分别查询左右子树并求和 return query(lson, x, y) + query(rson, x, y); } int main() { cin >> n; // 读取序列长度 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); // 读取序列数据 build(1, 1, n); // 构建线段树 cin >> m; // 读取查询数量 while(m--) { int x, y; scanf("%d%d", &x, &y); // 读取查询区间 printf("%lld\n", query(1, 1, n, x, y)); // 输出区间和 } return 0; }

浙公网安备 33010602011771号