POJ 3468 A Simple Problem with Integers

来源:互联网 发布:淘宝无线网址怎么转换 编辑:程序博客网 时间:2024/06/07 00:13

题目大意:

        现只有一个测例,给定一个整数序列共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>#defineMAXN100000//区间之和可能超过32位typedef__int64llg;typedefstruct {llgsum;//结点区间之和llginc;//区间中每个元素的增量//左右子树指针//不适用完全二叉树保存而减少存储空间intlft;intrht;} Node;Nodeseg[MAXN << 1];intcnt;//指示线段树总共有多少个结点用以拓展结点voidbuild( int tree, int lft, int rht ) {//sum和inc都为初始化默认值0//0为root指针intmid;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 );}}voidinsert( int tree, int i, int v, int lft, int rht ) {//tree结点的区间为[lft, rht]//添加元素编号为i,值为vintmid;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 );}voidupdate( int tree, int inc, int al, int ar, int lft, int rht ) {//[lft, rht]为tree的结点区间//al/ar为adding lft/rht,表示对区间[al, ar]中的每个元素都加上增量incintmid;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 );}}llgquery( int tree, int al, int ar, int lft, int rht ) {//[lft, rht]为tree的结点区间//[al, ar]为查询区间llginc;intmid;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 returnquery( seg[tree].lft, al, mid, lft, mid ) +    query( seg[tree].rht, mid + 1, ar, mid + 1, rht );}intmain() {intn, q;//数的总数以及查询次数intv;//临时接受输入的数列中元素的值intlft, rht;//临时接受查询区间charcmd;inti;//计数变量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>#defineMAXN100000typedef__int64llg;typedefstruct {llgsum;llginc;intlft;intrht;} Node;Nodeseg[MAXN << 1];intcnt;voidbuild( int tree, int lft, int rht ) {intmid;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 );}}voidinsert( int tree, int i, int v, int lft, int rht ) {intmid;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 );}voidupdate( int tree, int inc, int al, int ar, int lft, int rht ) {intmid;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 );}}llgquery( int tree, int al, int ar, int lft, int rht ) {llginc;intmid;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 returnquery( seg[tree].lft, al, mid, lft, mid ) +    query( seg[tree].rht, mid + 1, ar, mid + 1, rht );}intmain() {intn, q;intv;intlft, rht;charcmd;inti;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;}

0 0
原创粉丝点击