算法训练 操作格子
时间限制:1.0s 内存限制:256.0MB
问题描述
有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
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。
对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
考查线段树。单点更新、区间求和、区间最大值
#include <cstdio>
#define MAX ( 100000 + 10 )
int num[MAX];
int sum[MAX];
typedef struct {
int left;
int right;
int value;
int sum;
} SegmentTree;
SegmentTree tree[MAX * 20];
void buildSegmentTree( int root, int left, int right ) {
tree[root].left = left;
tree[root].right = right;
if( left == right ) {
tree[root].value = num[left];
tree[root].sum = num[left];
return ;
}
int mid = ( left + right ) / 2 ;
buildSegmentTree( 2 * root, left, mid );
buildSegmentTree( 2 * root + 1, mid + 1, right );
if( tree[2 * root].value >= tree[2 * root + 1].value ) {
tree[root].value = tree[2 * root].value;
}
else {
tree[root].value = tree[2 * root + 1].value;
}
tree[root].sum = tree[2 * root].sum + tree[2 * root + 1].sum;
}
int queryMax( int root, int left, int right ) {
if( tree[root].left > right || tree[root].right < left ) {
return 0;
}
if( left <= tree[root].left && tree[root].right <= right ) {
return tree[root].value;
}
int a = queryMax( 2 * root, left, right );
int b = queryMax( 2 * root + 1, left, right );
return ( a > b ? a : b );
}
int querySum( int root, int left, int right ) {
if( left <= tree[root].left && tree[root].right <= right ) {
return tree[root].sum;
}
if( tree[root].left > right || tree[root].right < left ) {
return 0;
}
int a = querySum( 2 * root, left, right );
int b = querySum( 2 * root + 1, left, right );
return a + b;
}
int update( int root, int pos, int val ) {
if( pos < tree[root].left || pos > tree[root].right ) {
return tree[root].value;
}
if( tree[root].left == pos && tree[root].right == pos ) {
tree[root].sum = val;
return tree[root].value = val;
}
int a = update( 2 * root, pos, val );
int b = update( 2 * root + 1, pos, val );
tree[root].value = ( a > b ? a : b );
tree[root].sum = tree[2 * root].sum + tree[2 * root + 1].sum;
return tree[root].value;
}
int main() {
int i;
int n, m;
int c, x, y;
while( scanf( "%d%d", &n, &m ) != EOF ) {
for( i = 1; i <= n; i++ ) {
scanf( "%d", &num[i] );
sum[i] = sum[i - 1] + num[i];
}
buildSegmentTree( 1, 1, n );
for( i = 1; i <= m; i++ ) {
getchar();
scanf( "%d%d%d", &c, &x, &y );
if( c == 1 ) {
num[x] = y;
update( 1, x, y );
}
else if( c == 2 ) {
printf( "%d\n", querySum( 1, x, y ) );
}
else if( c == 3 ) {
printf( "%d\n", queryMax( 1, x, y ) );
}
}
}
return 0;
}