线段树の一 区间和

线段树の一 区间和

具体线段树讲解:(搬运)http://blog.csdn.net/zearot/article/details/48299459

一:线段树基本概念

1:概述

线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)!

性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍

2:基本操作

线段树的主要操作有:

(1):线段树的构造 void build(int node, int begin, int end);

主要思想是递归构造,如果当前节点记录的区间只有一个值,则直接赋值,否则递归构造左右子树,最后回溯的时候给当前节点赋值

(2):区间查询int query(int node, int begin, int end, int left, int right);

(其中node为当前查询节点,begin,end为当前节点存储的区间,left,right为此次query所要查询的区间)

主要思想是把所要查询的区间[a,b]划分为线段树上的节点,然后将这些节点代表的区间合并起来得到所需信息

比如前面一个图中所示的树,如果询问区间是[0,2],或者询问的区间是[3,3],不难直接找到对应的节点回答这一问题。但并不是所有的提问都这么容易回答,比如[0,3],就没有哪一个节点记录了这个区间的最小值。当然,解决方法也不难找到:把[0,2]和[3,3]两个区间(它们在整数意义上是相连的两个区间)的最小值“合并”起来,也就是求这两个最小值的最小值,就能求出[0,3]范围的最小值。同理,对于其他询问的区间,也都可以找到若干个相连的区间,合并后可以得到询问的区间。

(3):区间或节点的更新 及 线段树的动态维护update (这是线段树核心价值所在,节点中的标记域可以解决N多种问题)

动态维护需要用到标记域,延迟标记等。

a:单节点更新

b:区间更新(线段树中最有用的)

需要用到延迟标记,每个结点新增加一个标记,记录这个结点是否被进行了某种修改操作(这种修改操作会影响其子结点)。对于任意区间的修改,我们先按照查询的方式将其划分成线段树中的结点,然后修改这些结点的信息,并给这些结点标上代表这种修改操作的标记。在修改和查询的时候,如果我们到了一个结点p,并且决定考虑其子结点,那么我们就要看看结点p有没有标记,如果有,就要按照标记修改其子结点的信息,并且给子结点都标上相同的标记,同时消掉p的标记。(优点在于,不用将区间内的所有值都暴力更新,大大提高效率,因此区间更新是最优用的操作)

3:主要应用

(1):区间最值查询问题 

(2):连续区间修改或者单节点更新的动态查询问题 

(3):多维空间的动态查询 

/*******************************
线段树V1.0
支持区间加、区间和查询
********************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000010
using namespace std;
struct node
{
	int left;//节点所代表区间左端
	int right;//节点所代表区间右端
	long long sum;//区间和
	long long add;//Lazy标记
} tree[N];
long long a[N];

void Build_Tree(int left,int right,int node)//left:当前区间左端 right:当前区间右端 node:当前节点
{
	tree[node].left=left;
	tree[node].right=right;
	if(left==right) tree[node].sum=a[left];
	else
	{
		int mid=(left+right)>>1;
		Build_Tree(left,mid,node<<1);
		Build_Tree(mid+1,right,node<<1|1);
		tree[node].sum=tree[node<<1].sum+tree[node<<1|1].sum;
	}
}

void Push_Down(int node)//标记下放 node:当前节点
{
	if(tree[node].add==0) return;
	tree[node<<1].add+=tree[node].add;
	tree[node<<1|1].add+=tree[node].add;
	tree[node<<1].sum+=tree[node].add*(tree[node<<1].right-tree[node<<1].left+1);
	tree[node<<1|1].sum+=tree[node].add*(tree[node<<1|1].right-tree[node<<1|1].left+1);
	tree[node].add=0;
}

void Push_Up(int node)//上推 node:当前节点
{
	tree[node].sum=tree[node<<1].sum+tree[node<<1|1].sum;
}

void Add_Range(int left,int right,int node,long long value)//区间加操作 left:操作区间左端点 right:操作区间右端点 node:当前节点 value:操作值
{
	if(tree[node].left>=left&&tree[node].right<=right)
	{
		tree[node].add+=value;
		tree[node].sum+=value*(tree[node].right-tree[node].left+1);
		return;
	}
	Push_Down(node);
	int mid=(tree[node].left+tree[node].right)>>1;
	if(left<=mid) Add_Range(left,right,node<<1,value);
	if(right>mid) Add_Range(left,right,node<<1|1,value);
	Push_Up(node);
}

long long Query_Sum(int left,int right,int node)//区间和查询 left:查询区间左端点 right:查询区间右端点 node:当前节点
{
	if(tree[node].left>right||tree[node].right<left)
	return 0;
	Push_Down(node);
	if(tree[node].left>=left&&tree[node].right<=right)
	return tree[node].sum;
	return Query_Sum(left,right,node*2)+Query_Sum(left,right,node*2+1);
}

int main()
{
	int n,m;//n:区间大小 m:操作次数
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	Build_Tree(1,n,1);
	while(m--)
	{
		int x,y,c;
		cin>>c>>x>>y;
		if(c==2)//查询
			cout<<Query_Sum(x,y,1)<<endl;
		if(c==1)   //操作
		{
			long long v;
			cin>>v;
			Add_Range(x,y,1,v);
		}
	}
	return 0;
}

  

时间: 2024-10-11 13:46:53

线段树の一 区间和的相关文章

HDU 1556 Color the ball(线段树:区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1556 题意: N个气球,每次[a,b]之间的气球涂一次色,统计每个气球涂色的次数. 思路: 这道题目用树状数组和线段树都可以,拿这道题来入门一下线段树的区间更新. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 1000

hihoCode 1078 : 线段树的区间修改

#1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格——小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问——小Hi给出一段

Balanced Lineup(线段树之区间查找最大最小值)

传送门 线段树的区间查找最大最小值模板. 裸的线段树 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include <queue> #include <vector> #include <cstdlib> #include <algorithm> #define ls

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都是开平方,同一个数更新有限次数就一直是1了,所以可以这样优化 #include <stdio.h> #include<math.h> #define N 100010 #define LL __int64 #define lson l,m,rt<<1 #define rson

hiho一下20周 线段树的区间修改

线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格--小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问--小Hi给出一段区间[L, R]

2016年湖南省第十二届大学生计算机程序设计竞赛---Parenthesis(线段树求区间最值)

原题链接 http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1809 Description Bobo has a balanced parenthesis sequence P=p1 p2…pn of length n and q questions. The i-th question is whether P remains balanced after pai and pbi  swapped. Note that questions ar

杭电1698--Just a Hook(线段树, 区间更新)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1698 线段树, 区间更新, 用到了Lazy思想.利用已更新区间来减少未更新区间用时.(自己的理解, 应该是对的) #include <cstdio>#include <cstring>#include <iostream>using namespace std;int Node[100100<<2], n, m, lazy[100100<<2];void