蓝桥杯算法训练_格子操作_线段树_区间和与区间最值
2015-02-25 16:08
453 查看
这题设计最基本的线段树应用,同时考察区间和与区间最值,我采用一个造树函数,一个更新函数和两个查询查询函数,两个查询函数分别返回区间和与区间最大值。
问题描述
有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 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。
对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
上代码,道理都在注释里:
问题描述
有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 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。
对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
上代码,道理都在注释里:
<span style="color:#000000;">#include <iostream> #include<stdio.h> using namespace std; int n,m,p,x,y; long long int num[100005];//数组元素存放处 long long int sum[100005]={0};//前i个元素和,方便造树时用 long long int father[100005];//每个数组中元素对应线段树中的叶结点 class node { public: int left,right;//左右子节点标 int lbond,rbond;//节点表示的左右区间 long long int sum_V;//节点区间和 long long int max_V;//区间最大值 }; node nodes[400005];//4倍数组大小的节点数组,用来模拟线段树 void build_tree(int i,int l,int r)//线段树构造函数 { nodes[i].sum_V=sum[r]-sum[l-1];//直接通过sum数组赋值区间和 nodes[i].lbond=l;//赋值区间左右范围 nodes[i].rbond=r; //cout<<i<<"-------"<<nodes[i].sum_V<<endl; if(l==r)//如果是叶节点,用-1表示没有子孙,最大值就是他自己 { nodes[i].left=-1; nodes[i].right=-1; nodes[i].max_V=num[l]; father[l]=i;//数组元素对应线段树中叶节点下标 }else { nodes[i].left=i<<1;//乘2拿没用过的节点做左右子节点 nodes[i].right=(i<<1)+1; build_tree(i<<1,l,(l+r)/2);//递归构造 build_tree((i<<1)+1,(l+r)/2+1,r); nodes[i].max_V=max(nodes[(i<<1)].max_V,nodes[(i<<1)+1].max_V); } } void update(int i)//节点更新函数,参数只有节点下标,原数组更新在main函数里 { if(nodes[i].left!=-1&&nodes[i].right!=-1)//若不是叶节点 { nodes[i].sum_V=nodes[nodes[i].left].sum_V+nodes[nodes[i].right].sum_V;//和为左右儿子和的和 nodes[i].max_V=max(nodes[nodes[i].left].max_V,nodes[nodes[i].right].max_V);//最大值为左右儿子中大者 } if((i>>1)>0)//若非根节点,向上递归更新 { update(i>>1); } return; } long long int Qsum(int i,int l,int r)//区间和查询函数 { //cout<<"ask-----"<<i<<endl; if(nodes[i].lbond>=l&&nodes[i].rbond<=r)//若节点范围全在查询范围里 return nodes[i].sum_V; else if(nodes[i].lbond>r||nodes[i].rbond<l)//若节点范围完全不在查询范围里 return 0; else//若部分在查询范围里 { return Qsum(nodes[i].left,l,r)+Qsum(nodes[i].right,l,r); } } long long int Qmax(int i,int l,int r)//区间最大值查询函数 { if(nodes[i].lbond>=l&&nodes[i].rbond<=r) return nodes[i].max_V; else if(nodes[i].lbond>r||nodes[i].rbond<l) return -1000000000000;//若节点范围完全不在查询范围里,返回极小的一个数 else { return max(Qmax(nodes[i].left,l,r),Qmax(nodes[i].right,l,r)); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%I64d",&num[i]); sum[i]=sum[i-1]+num[i]; } build_tree(1,1,n); for(int i=0;i<m;i++) { scanf("%d%d%d",&p,&x,&y); if(p==1) { //更新原数组元素和对应叶节点 num[x]=y; nodes[father[x]].sum_V=y; nodes[father[x]].max_V=y; //从叶节点开始往上更新 update(father[x]); }else if(p==2) { //查询区间和 printf("%I64d\n",Qsum(1,x,y)); }else if(p==3) { //查询区间最值 printf("%I64d\n",Qmax(1,x,y)); } } //cout << "Hello world!" << endl; return 0; } </span>
相关文章推荐
- 蓝桥杯算法训练——操作格子(线段树+单点更新+区间求和+求最大值)
- 蓝桥杯 算法训练 操作格子 (线段树)
- 算法训练 操作格子 线段树 单点修改,求区间和,区间最大值
- 蓝桥杯_法训练—操作格子(线段树点更新与区间查询)
- 蓝桥杯 算法训练 操作格子 (线段树模板)
- [蓝桥杯]算法训练 操作格子-链式线段树
- 蓝桥杯 算法训练 操作格子(线段树)
- 蓝桥杯 ALGO-8 算法训练 操作格子(线段树)
- 蓝桥杯 算法训练 操作格子(线段树,点更新)
- 蓝桥杯 算法训练 操作格子 (最基本的线段树)
- 蓝桥杯 算法训练 操作格子 [ 线段树 ]
- 蓝桥杯 算法训练 操作格子
- 蓝桥杯-算法训练 操作格子
- 蓝桥杯_ 算法训练 操作格子
- 算法-蓝桥杯-算法训练 操作格子(C++)
- 蓝桥杯 算法训练 操作格子
- 蓝桥杯 算法训练 操作格子
- 蓝桥杯-算法训练--ALGO-8 操作格子
- 蓝桥杯 算法训练 操作格子 JAVA
- 算法训练 操作格子 线段树