南邮OJ 2027 操作序列
2014-03-26 20:31
92 查看
链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2027
题目:
时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte
总提交:146 测试通过:26
描述
给出一初始序列a1, a2,...,an,下面有m个操作(x, l, r) : 对于a[l], a[l+1],...,a[r]都加上x.
输出m个操作结束后的序列.
输入
第一行两个整数n,m(0 <= n,m <= 100000),n表序列{A}的长度, m表操作的个数。
第二行有n 个整数ai(-10000 <= ai <= 10000)。
下面m行,每一行表示一个操作,一个操作表示为3个整数x, l, r(1 <= l <= r <= n, |x|<=1000)。
输出
输出结果序列。数据已改正,行末没有空格!
样例输入
5 3
1 2 3 -4 5
2 1 1
-3 3 5
0 1 5
样例输出
3 2 0 -7 2
提示
null
解题思路:
解法1:
这道题目,主要涉及的就是一个区间更新的问题。将数组a的[L,R]区间内的每个元素加x。我们可以这样来解决这个问题,将区间[L,R]分解为[1,R]和[1,L-1],这样原问题就可以转化为,将[1,R]的每个元素加x,再将[1,L-1]的每个元素加(-x),我们可以用一个数组sum来记录这些更新。sum[i] = x,表示对数组a从第1个元素到第i个元素,每个元素加上x。这样的话最后我们对a的更新就变成了这样:a[i] = a[i] + sum[i] + sum[i+1] + sum[i+2] + ...
+ sum
;我们可以优化一下,将sum数组进行处理,使其成为前缀和数组(sum[i] = b[1] + b[2] + ... + b[i] )。这样对a的更新就变成了:a[i] = a[i] + sum
- sum[i-1];
解法2:
线段树区间更新。
解法1代码:
解法2代码:
题目:
操作序列
时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte总提交:146 测试通过:26
描述
给出一初始序列a1, a2,...,an,下面有m个操作(x, l, r) : 对于a[l], a[l+1],...,a[r]都加上x.
输出m个操作结束后的序列.
输入
第一行两个整数n,m(0 <= n,m <= 100000),n表序列{A}的长度, m表操作的个数。
第二行有n 个整数ai(-10000 <= ai <= 10000)。
下面m行,每一行表示一个操作,一个操作表示为3个整数x, l, r(1 <= l <= r <= n, |x|<=1000)。
输出
输出结果序列。数据已改正,行末没有空格!
样例输入
5 3
1 2 3 -4 5
2 1 1
-3 3 5
0 1 5
样例输出
3 2 0 -7 2
提示
null
解题思路:
解法1:
这道题目,主要涉及的就是一个区间更新的问题。将数组a的[L,R]区间内的每个元素加x。我们可以这样来解决这个问题,将区间[L,R]分解为[1,R]和[1,L-1],这样原问题就可以转化为,将[1,R]的每个元素加x,再将[1,L-1]的每个元素加(-x),我们可以用一个数组sum来记录这些更新。sum[i] = x,表示对数组a从第1个元素到第i个元素,每个元素加上x。这样的话最后我们对a的更新就变成了这样:a[i] = a[i] + sum[i] + sum[i+1] + sum[i+2] + ...
+ sum
;我们可以优化一下,将sum数组进行处理,使其成为前缀和数组(sum[i] = b[1] + b[2] + ... + b[i] )。这样对a的更新就变成了:a[i] = a[i] + sum
- sum[i-1];
解法2:
线段树区间更新。
解法1代码:
#include <iostream> #include <cstring> using namespace std; const int MAXN = 100010; int a[MAXN], sum[MAXN];//sum[i] = x数组,表示a[i]数组从1到i每个元素加x int main() { std::ios::sync_with_stdio(false); memset(a, 0, sizeof(a)); memset(sum, 0, sizeof(sum)); int n, m; cin >> n >> m; for(int i = 1; i <= n; i++) cin >> a[i]; while(m--) { int l, r, x; cin >> x >> l >> r; sum[r] += x; sum[l-1]-= x; } for(int i = 1; i <= n; i++) sum[i] += sum[i-1]; for(int i = 1; i <= n; i++) a[i] += (sum - sum[i-1]); for(int i = 1; i <= n; i++) { if(i - 1) cout << " "; cout << a[i]; } cout << endl; return 0; }
解法2代码:
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 100010; struct Tree { int left, right, x; }; Tree tree[4 * MAXN]; int first = 1; void build_tree(int l, int r, int i) { tree[i].left = l; tree[i].right = r; tree[i].x = 0; if(l == r) { return ; } int mid = (l + r) >> 1; build_tree(l, mid, i + i); build_tree(mid + 1, r, i + i + 1); } void update(int l, int r, int i, int x) { if(l == tree[i].left && r == tree[i].right) { tree[i].x += x; return; } int mid = (tree[i].left + tree[i].right) >> 1; if(r <= mid) { update(l, r, i + i, x); } else { if(l > mid) { update(l, r, i + i + 1, x); } else { update(l, mid, i + i, x); update(mid + 1, r, i + i + 1, x); } } } void print(int l, int r, int i, int num) { if(l == r) { if(!first) cout << " "; else first = 0; cout << tree[i].x + num; return ; } int mid = (l + r) >> 1; print(l, mid, i + i, tree[i].x + num); print(mid + 1, r, i + i + 1, tree[i].x + num); } int main() { std::ios::sync_with_stdio(false); int n, m; cin >> n >> m; tree[1].left = 1, tree[1].right = n, tree[1].x = 0; build_tree(1, n, 1); for(int i = 1; i <= n; i++) { int x; cin >> x; update(i, i, 1, x); } while(m--) { int x, l, r; cin >> x >> l >> r; update(l, r, 1, x); } print(1, n, 1, 0); return 0; }
相关文章推荐
- 南邮 OJ 2027 操作序列
- 南邮 OJ 1043 合法序列
- 南邮 OJ 2024 入栈序列和出栈序列
- 【HPU OJ 1310 】序列的区间操作 【思维】
- 南邮 OJ 1047 图的深度优先遍历序列
- 南邮 OJ 1048 图的宽度优先遍历序列
- 南邮 OJ 1618 合法序列
- 2027-操作序列
- GFOJ686 序列操作(分段DP,未高精)
- 南邮 OJ 1004 线性表操作
- hdu 5146 Sequence(序列操作)
- BZOJ 1858 序列操作 (线段树)
- H.264句法和语法总结(八)参考图像序列标记 (marking)操作的语义
- SCOI2010序列操作--线段树迷之维护
- 九度OJ 1533 最长上升子序列 -- 动态规划
- oracle 序列操作
- python题目-----序列反序操作
- python备忘六:list 列表之序列通用操作
- 华为OJ(最长公共子串及公共最长子序列)
- bzoj1858 [Scoi2010]序列操作