题目大意

一个数列,每次操作可以是将某区间数字都加上一个相同的整数,也可以是询问一个区间中所有数字的和。(这里区间指的是数列中连续的若干个数)对每次询问给出结果。

思路

对于区间的查找更新操作,可以考虑使用伸展树、线段树等数据结构。这里使用线段树来解决。需要注意的是,对于一个区间的增加操作,如果每次都走到叶子节点进行更新,则必定超时,因此lazy方法来解决。即如果能从当前节点获得所需要的信息,则不必走到子节点。

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
using namespace std;
#define MAX_COUNT 100005
#define MAX(a, b) a>b? a:b
#define MIN(a, b) a<b? a:b //查找两个相交的区间的并长度(即两个区间覆盖的总长度)
int Interval(int beg1, int end1, int beg2, int end2){
int tmp = MAX(end1, end2);
//注意不要 MAX(end1, end2) -MIN(beg1, beg2), 因为这样做在编译的时候宏定义展开,
//和三目运算符一块,优先级导致结果出错!!!! tmp -= MIN(beg1, beg2);
return (end1 - beg1 + end2 - beg2) - tmp + ;
} int gNumCount, gQueryCount; //总的数字的数目,总的查询次数 int gNumber[MAX_COUNT]; //线段树节点的数组 //线段树节点的定义
struct TreeNode{
int begin; //该节点覆盖区间的左边界
int end; //该节点覆盖区间的右边界 long long sum; //该节点覆盖区间的当前sum值,不包括 inc 可能增加的那些值(即实际的和应该为 sum + inc *(end - begin+1)
long long inc; //该节点覆盖区间中的那些点 应该被增加的值(注意是该区间的所有点)
}; struct TreeNode gTreeNodes[MAX_COUNT*]; //自底向上的更新,将左右子的 sum 值相加得到 该节点的sum值
void PushUp(int node_index){
int left_child = * node_index + ;
int right_child = * node_index + ;
gTreeNodes[node_index].sum = gTreeNodes[left_child].sum + gTreeNodes[right_child].sum;
} //自顶向下的更新操作,当该节点不能被查询区间全部覆盖,则需要向下走,去其子节点位置进行查询
//在查询之前,需要将 inc 值传递到子节点,同时该节点的sum值更新,inc值清零
void PushDown(int node_index){
TreeNode* node = gTreeNodes + node_index;
int left_child = * node_index + ;
int right_child = * node_index + ;
node->sum += node->inc*(node->end - node->begin + );
gTreeNodes[left_child].inc += node->inc;
gTreeNodes[right_child].inc += node->inc;
node->inc = ;
}
void BuildTree(int node_index, int beg, int end){
TreeNode* node = gTreeNodes + node_index;
node->inc = node->sum = ;
node->begin = beg;
node->end = end;
if (beg == end){
node->sum = gNumber[beg];
return;
}
int mid = (beg + end) / , left_child = * node_index + , right_child = * node_index + ;
BuildTree(left_child, beg, mid);
BuildTree(right_child, mid + , end); //自底向上更新
PushUp(node_index);
} void Add(int node_index, int beg, int end, long long c){
TreeNode* node = gTreeNodes + node_index;
int left_child = * node_index + , right_child = * node_index + , mid = (node->begin + node->end) / ;
if (node->begin > end || node->end < beg){
return;
}
//如果当前结点被查询区间全部覆盖,则不向下传递,直接将inc值增加
if (node->begin >= beg && node->end <= end){
node->inc += c;
return;
}
//如果节点不能被查询区间全部覆盖,则需要分裂节点向下传递,此时的sum值需要增加(inc * 两区间重合的长度)
//而同时 inc 值保持不变
node->sum += (Interval(node->begin, node->end, beg, end) * c);
int end1 = MIN(end, mid);
int beg1 = MAX(beg, mid + ); Add(left_child, beg, end1, c);
Add(right_child, beg1, end, c);
} long long QuerySum(int node_index, int beg, int end){
TreeNode* node = gTreeNodes + node_index;
// printf("node %d's sum = %d\n", node_index, gTreeNodes[node_index].sum);
// printf("node->beg = %d, node->end = %d, beg = %d, end = %d\n", node->begin, node->end, beg, end); int left_child = * node_index + , right_child = * node_index + , mid = (node->begin + node->end) / ;
long long sum = ;
if (node->begin > end || node->end < beg){
return sum;
}
if (node->begin >= beg && node->end <= end){
sum += (node->sum + node->inc*(node->end - node->begin + ));
}
else{
//向下分裂的更新操作
PushDown(node_index); int end1 = MIN(end, mid);
int beg1 = MAX(beg, mid + );
long long sum_left = QuerySum(left_child, beg, end1);
long long sum_right = QuerySum(right_child, beg1, end);
sum += (sum_left + sum_right);
}
return sum;
} int main(){
scanf("%d %d", &gNumCount, &gQueryCount);
for (int i = ; i < gNumCount; i++){
scanf("%d", gNumber + i);
}
BuildTree(, , gNumCount - ); char op;
int a, b;
long long c;
long long result;
for (int i = ; i < gQueryCount; i++){
getchar();
scanf("%c", &op);
if (op == 'C'){
scanf("%d %d %lld", &a, &b, &c);
Add(, a- , b-, c);
/*
for (int k = 0; k < 27; k++){
printf("node[%d]'s sum = %lld, inc = %lld\n", k, gTreeNodes[k].sum, gTreeNodes[k].inc);
}
*/
}
else if (op == 'Q'){
scanf("%d %d", &a, &b);
result = QuerySum(, a-, b-);
printf("%lld\n", result);
}
}
return ;
}

poj_3468 线段树的更多相关文章

  1. poj_3468线段树成段更新求区间和

    #include<iostream> #include<string.h> #include<cstdio> long long num[100010]; usin ...

  2. poj_3468,线段树成段更新

    参考自http://www.notonlysuccess.com/index.php/segment-tree-complete/ #include<iostream> #include& ...

  3. POJ_3468 A Simple Problem with Integers 【线段树区间查询+修改】

    一.题目 POJ3468 二.分析 裸的线段树区间查询+修改. 三.AC代码 #include <cstdio> #include <iostream> #include &l ...

  4. 线段树(成段更新) POJ 3468 A Simple Problem with Integers

    题目传送门 /* 线段树-成段更新:裸题,成段增减,区间求和 注意:开long long:) */ #include <cstdio> #include <iostream> ...

  5. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  6. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  7. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  8. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  9. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

随机推荐

  1. 【WPF】ListBox使用UserContrl作为子控件,引入UserContrl界面

    <ListBox x:Name="housePlansLB" Margin="0" ItemsSource="{Binding HousePla ...

  2. lighttpd + php 移植配置

    buildroot 内添加 lighttpd 和php 等相关选项 // make menuconfig Target packages ---> Interpreter languages a ...

  3. CAS (3) —— Mac下配置CAS客户端经代理访问Tomcat CAS

    CAS (3) -- Mac下配置CAS客户端经代理访问Tomcat CAS tomcat版本: tomcat-8.0.29 jdk版本: jdk1.8.0_65 nginx版本: nginx-1.9 ...

  4. 【json】Jackson的使用

    Jackson所有的操作都是通过ObjectMapper对象实例来操作的,可以重用这个对象实例. 首先定义一个实例: ObjectMapper mapper = new ObjectMapper(); ...

  5. sublime text2 配置

    2.使用Package Control组件安装 也可以安装package control组件,然后直接在线安装: 按Ctrl+`调出console 粘贴以下代码到底部命令行并回车:import url ...

  6. [转]Python与设计模式

    一.创建类设计模式 前言 什么样的程序员是一个好的程序员?学会很多门编程语言,就是一个好的程序员了么?事实上,学会一门编程语言不是一件很难的事,而“学会”一门编程语言是非常难的一件事.前一个“会”强调 ...

  7. Java实现一个简单的缓存方法

    缓存是在web开发中经常用到的,将程序经常使用到或调用到的对象存在内存中,或者是耗时较长但又不具有实时性的查询数据放入内存中,在一定程度上可以提高性能和效率.下面我实现了一个简单的缓存,步骤如下. 创 ...

  8. MySQL多表数据记录查询详解

    在实际应用中,经常需要实现在一个查询语句中显示多张表的数据,这就是所谓的多表数据记录连接查询,简称来年将诶查询. 在具体实现连接查询操作时,首先将两个或两个以上的表按照某个条件连接起来,然后再查询到所 ...

  9. [转自setting]神奇的jQuery

    前言 之前的项目也一直都是在用jQuery,遇到问题就翻翻API,也从来没有进行过比较系统的总结和整理.最近由于要做个培训,因为比较系统的归纳了一下javascript的相关知识,顺手做个笔记.说到j ...

  10. 你可能并不需要一个 CTO

    转自:http://dbanotes.net/CTO 有朋友在微信里让我给推荐一个 CTO.说是一家公司在找人,据说「项目不错」,因为之前的业务不是很互联网,现在有一个新的项目要做,要做一个社会化电商 ...