题目大意:
现只有一个测例,给定一个整数序列共N个元素(1 ≤ N ≤ 100,000,其中元素范围为[-1000000000, 1000000000],并且编号为1 ~ N)和Q此询问(1 ≤ Q ≤ 100,000),共有两种询问操作,一种是"C a b c",表示对编号区间[a, b]的每个元素都加上增量c,另一种是"Q a b",表示要求输出编号区间[a, b]中所有元素之和,每次输出占一行。
注释代码:
/*
* Problem ID : POJ 3468 A Simple Problem with Integers
* Author : Lirx.t.Una
* Language : C
* Run Time : 1485 ms
* Run Memory : 4856 KB
*/
#include <stdio.h>
#define MAXN 100000
//区间之和可能超过32位
typedef __int64 llg;
typedef struct {
llg sum;//结点区间之和
llg inc;//区间中每个元素的增量
//左右子树指针
//不适用完全二叉树保存而减少存储空间
int lft;
int rht;
} Node;
Node seg[MAXN << 1];
int cnt;//指示线段树总共有多少个结点用以拓展结点
void
build( int tree, int lft, int rht ) {
//sum和inc都为初始化默认值0
//0为root指针
int mid;
if ( lft != rht ) {//如果到达叶子结点则不再有儿子
//左右指针指向NULL(默认值)即可
//赋予指针域
seg[tree].lft = ++cnt;
seg[tree].rht = ++cnt;
mid = ( lft + rht ) >> 1;
build( seg[tree].lft, lft, mid );
build( seg[tree].rht, mid + 1, rht );
}
}
void
insert( int tree, int i, int v, int lft, int rht ) {
//tree结点的区间为[lft, rht]
//添加元素编号为i,值为v
int mid;
if ( lft == rht ) {//到达叶子结点
seg[tree].sum = v;
return ;
}
seg[tree].sum += v;//没到达叶子结点,则i必定包含在[lft, rht]之中
mid = ( lft + rht ) >> 1;
if ( i <= mid ) insert( seg[tree].lft, i, v, lft, mid );
else insert( seg[tree].rht, i, v, mid + 1, rht );
}
void
update( int tree, int inc, int al, int ar, int lft, int rht ) {
//[lft, rht]为tree的结点区间
//al/ar为adding lft/rht,表示对区间[al, ar]中的每个元素都加上增量inc
int mid;
if ( lft == al && ar == rht ) {//命中
seg[tree].inc += inc;
return ;
}
//由于未命中,所以[al, ar]真包含于[lft, rht]
//由于只有遇到命中的情况才能改变当前结点的inc
//所以在这里不得不将inc[al, ar]加至当前结点的inc中去
seg[tree].sum += inc * ( ar - al + 1 );
mid = ( lft + rht ) >> 1;
if ( ar <= mid )
update( seg[tree].lft, inc, al, ar, lft, mid );
else if ( al > mid )
update( seg[tree].rht, inc, al, ar, mid + 1, rht );
else {
update( seg[tree].lft, inc, al, mid, lft, mid );
update( seg[tree].rht, inc, mid + 1, ar, mid + 1, rht );
}
}
llg
query( int tree, int al, int ar, int lft, int rht ) {
//[lft, rht]为tree的结点区间
//[al, ar]为查询区间
llg inc;
int mid;
if ( lft == al && ar == rht )//命中
return seg[tree].sum + ( rht - lft + 1 ) * seg[tree].inc;
//未命中,说明[al, ar]在[lft, rht]的子结点中,必须向下查询
//因此必须将当前结点的inc往下更新到子结点中去
seg[tree].sum += ( rht - lft + 1 ) * seg[tree].inc;//先将自己的inc加到sum中去
inc = seg[tree].inc;
//由于往下更新时两颗子树必定都要更新,因此向下更新时必定第一层就命中
//因此没有必要调用update函数直接加两行代码就行,可以节省函数调用的时间和空间开销
seg[ seg[tree].lft ].inc += inc;
seg[ seg[tree].rht ].inc += inc;
seg[tree].inc = 0;//加完之后就清零
mid = ( lft + rht ) >> 1;
if ( ar <= mid ) return query( seg[tree].lft, al, ar, lft, mid );
else if ( al > mid ) return query( seg[tree].rht, al, ar, mid + 1, rht );
else return
query( seg[tree].lft, al, mid, lft, mid ) +
query( seg[tree].rht, mid + 1, ar, mid + 1, rht );
}
int
main() {
int n, q;//数的总数以及查询次数
int v;//临时接受输入的数列中元素的值
int lft, rht;//临时接受查询区间
char cmd;
int i;//计数变量
scanf("%d%d", &n, &q);
build( 0, 1, n );
for ( i = 1; i <= n; i++ ) {
scanf("%d", &v);
insert( 0, i, v, 1, n );
}
while ( q-- ) {
scanf("\n%c%d%d", &cmd, &lft, &rht);
switch ( cmd ) {
case 'Q' :
printf("%I64d\n", query( 0, lft, rht, 1, n));
break;
case 'C' :
scanf("%d", &v);
update( 0, v, lft, rht, 1, n );
break;
default : break;
}
}
return 0;
}
无注释代码:
#include <stdio.h>
#define MAXN 100000
typedef __int64 llg;
typedef struct {
llg sum;
llg inc;
int lft;
int rht;
} Node;
Node seg[MAXN << 1];
int cnt;
void
build( int tree, int lft, int rht ) {
int mid;
if ( lft != rht ) {
seg[tree].lft = ++cnt;
seg[tree].rht = ++cnt;
mid = ( lft + rht ) >> 1;
build( seg[tree].lft, lft, mid );
build( seg[tree].rht, mid + 1, rht );
}
}
void
insert( int tree, int i, int v, int lft, int rht ) {
int mid;
if ( lft == rht ) {
seg[tree].sum = v;
return ;
}
seg[tree].sum += v;
mid = ( lft + rht ) >> 1;
if ( i <= mid ) insert( seg[tree].lft, i, v, lft, mid );
else insert( seg[tree].rht, i, v, mid + 1, rht );
}
void
update( int tree, int inc, int al, int ar, int lft, int rht ) {
int mid;
if ( lft == al && ar == rht ) {
seg[tree].inc += inc;
return ;
}
seg[tree].sum += inc * ( ar - al + 1 );
mid = ( lft + rht ) >> 1;
if ( ar <= mid )
update( seg[tree].lft, inc, al, ar, lft, mid );
else if ( al > mid )
update( seg[tree].rht, inc, al, ar, mid + 1, rht );
else {
update( seg[tree].lft, inc, al, mid, lft, mid );
update( seg[tree].rht, inc, mid + 1, ar, mid + 1, rht );
}
}
llg
query( int tree, int al, int ar, int lft, int rht ) {
llg inc;
int mid;
if ( lft == al && ar == rht )
return seg[tree].sum + ( rht - lft + 1 ) * seg[tree].inc;
seg[tree].sum += ( rht - lft + 1 ) * seg[tree].inc;
inc = seg[tree].inc;
seg[ seg[tree].lft ].inc += inc;
seg[ seg[tree].rht ].inc += inc;
seg[tree].inc = 0;
mid = ( lft + rht ) >> 1;
if ( ar <= mid ) return query( seg[tree].lft, al, ar, lft, mid );
else if ( al > mid ) return query( seg[tree].rht, al, ar, mid + 1, rht );
else return
query( seg[tree].lft, al, mid, lft, mid ) +
query( seg[tree].rht, mid + 1, ar, mid + 1, rht );
}
int
main() {
int n, q;
int v;
int lft, rht;
char cmd;
int i;
scanf("%d%d", &n, &q);
build( 0, 1, n );
for ( i = 1; i <= n; i++ ) {
scanf("%d", &v);
insert( 0, i, v, 1, n );
}
while ( q-- ) {
scanf("\n%c%d%d", &cmd, &lft, &rht);
switch ( cmd ) {
case 'Q' :
printf("%I64d\n", query( 0, lft, rht, 1, n));
break;
case 'C' :
scanf("%d", &v);
update( 0, v, lft, rht, 1, n );
break;
default : break;
}
}
return 0;
}