蓝桥杯 算法训练 操作格子
2015-02-25 18:47
471 查看
问题描述
有n个格子,从左到右放成一排,编号为1-n。共有m次操作,有3种操作类型:
1.修改一个格子的权值,
2.求连续一段格子权值和,
3.求连续一段格子的最大值。
对于每个2、3操作输出你所求出的结果。
输入格式
第一行2个整数n,m。接下来一行n个整数表示n个格子的初始权值。
接下来m行,每行3个整数p,x,y,p表示操作类型,
p=1时表示修改格子x的权值为y,
p=2时表示求区间[x,y]内格子权值和,
p=3时表示求区间[x,y]内格子最大的权值。
输出格式
有若干行,行数等于p=2或3的操作总数。每行1个整数,对应了每个p=2或3操作的结果。
样例输入
4 31 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
63
数据规模与约定
对于20%的数据n <= 100,m <= 200。对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
解题思路
由数据规模得,使用int数据类型即可。注意,区间计数是从1开始的。
按照一般的思路提交,可是超时,刚好看到题目锦囊提示使用线段树。
线段树(Segment Tree)是一种二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左子树表示的区间为[a,(a+b)/2],右子树表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树。叶节点数目为N,即整个线段区间的长度。
简单的说,顾名思义,就是将一段线段(如:1-10),不断的划分,形成一棵树。
在这里,使用数组存放满二叉树,那数组的大小是多少呢?
在构建和利用线段树的过程中,充分使用了分治的思想。
题目中说,“p=1时表示修改格子x的权值为y”,这个x代表的是格子的位置。
创建的是1到n的线段树,其实每个结点的权重是不需要额外存储的,只需知道权重的和与最大值。叶子结点的sum和max即为权重。
注意,数组从1开始存储,利于二叉树结点位置的确定。
找了好几个小时的错误,原来是在找最大值的地方,把right写成了left,悲哀!忽然有种高中做数学题的悲哀。
代码实现
数组或容器
只能满足前50%的数据。注意,在case语句中最好不要定义并初始化变量,常引起错误。
case后加大括号,可定义局部变量。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main(void) { int n, m; cin >> n >> m; vector<int> v; while(n--) { int tmp; cin >> tmp; v.push_back(tmp); } while(m--) { int p, x, y; cin >> p >> x >> y; int sum = 0; int max = 0; switch(p) { case 1 : v[x-1] = y; break; case 2 : for(int i = x; i <= y; i++) { sum += v[i - 1]; } cout << sum << endl; break; case 3 : for(int i = x; i <= y; i++) { if(v[i - 1] > max) { max = v[i - 1]; } } cout << max << endl; break; default : break; } } return 0; }
线段树
这里使用数组存放线段树,其实和线段树相关的操作只涉及到4种:构建线段树
改变线段树中某个结点的值
求某区间的结点权重的和
求某区间的结点权重的最大值
只是存放线段树的数组的大小还没搞清楚,从coolnote下载的测试数据表明:
当n为100000时,最后一个不为0的数组索引为262142。
给定【1,n】,建立线性二叉树,其层数是确定的,根据二分原理,其层数为m=上取整(log(n))+1 , 那么数组上界为这棵满二叉树所有节点个数: 2^m-1=2^(上取整(log(n))+1)-1
举个例子,n=5,树层数为m=4,上界为2^4-1=15
n=6,树层数为m=4,上界为2^4-1=15
n=100000,树层数为m=18,上界为2^18-1=262143
#include <iostream> #include <cstring> using namespace std; typedef struct SNode { int max, sum; int left, right; } SNode; SNode t[300000]; int two_max(int a, int b) { return a > b ? a : b; } void build(int pos, int l, int r) { t[pos].left = l; t[pos].right = r; t[pos].max = 0; t[pos].sum = 0; if(l == r) { return; } build(pos * 2, l, (l + r) / 2); build(pos * 2 + 1, (l + r) / 2 + 1, r); } void change(int pos, int v, int w) { if(t[pos].left == v && t[pos].right == v) { t[pos].sum = w; t[pos].max = w; return; } int middle = (t[pos].left + t[pos].right) / 2; if(v <= middle) { change(pos * 2, v, w); } else { change(pos * 2 + 1, v, w); } t[pos].sum = t[pos * 2].sum + t[pos * 2 + 1].sum; t[pos].max = two_max(t[pos * 2].max, t[pos * 2 + 1].max); } int get_sum(int pos, int l, int r) { if(t[pos].left == l && t[pos].right == r) { return t[pos].sum; } int middle = (t[pos].left + t[pos].right) / 2; if(r <= middle) { return get_sum(pos * 2, l, r); } if(l > middle) { return get_sum(pos * 2 + 1, l, r); } return get_sum(pos * 2, l, middle) + get_sum(pos * 2 + 1, middle + 1, r); } int get_max(int pos, int l, int r) { if(t[pos].left == l && t[pos].right == r) { return t[pos].max; } int middle = (t[pos].left + t[pos].right) / 2; if(r <= middle) { return get_max(pos * 2, l, r); } if(l > middle) { return get_max(pos * 2 + 1, l, r); } return two_max(get_max(pos * 2, l, middle), get_max(pos * 2 + 1, middle + 1, r)); } int main(void) { memset(t, 0, sizeof(t)); int n, m; cin >> n >> m; build(1, 1, n); for(int i = 1; i <= n; i++) { int tmp; cin >> tmp; change(1, i, tmp); } while(m--) { int p, x, y; cin >> p >> x >> y; switch(p) { case 1 : change(1, x, y); break; case 2 : cout << get_sum(1, x, y) << endl; break; case 3 : cout << get_max(1, x, y) << endl; break; } } return 0; }
相关文章推荐
- 蓝桥杯 算法训练 操作格子(线段树,点更新)
- 蓝桥杯 ALGO-8 算法训练 操作格子(线段树)
- 蓝桥杯算法训练——操作格子(线段树+单点更新+区间求和+求最大值)
- 蓝桥杯 算法训练 操作格子
- 蓝桥杯 算法训练 操作格子 JAVA
- 蓝桥杯 算法训练 操作格子 (最基本的线段树)
- 蓝桥杯 算法训练 操作格子 (线段树)
- 蓝桥杯_ 算法训练 操作格子
- 蓝桥杯-算法训练 操作格子
- 蓝桥杯 算法训练 操作格子 (线段树模板)
- 蓝桥杯-算法训练--ALGO-8 操作格子
- 蓝桥杯算法训练_格子操作_线段树_区间和与区间最值
- 算法-蓝桥杯-算法训练 操作格子(C++)
- 蓝桥杯 算法训练 操作格子 [ 线段树 ]
- [蓝桥杯]算法训练 操作格子-链式线段树
- 蓝桥杯 算法训练 操作格子
- 蓝桥杯 算法训练 操作格子(线段树)
- 蓝桥杯 算法训练 操作格子
- 蓝桥杯_算法训练_操作格子
- 算法训练 操作格子