• 线段树の一 区间和


    线段树の一 区间和

    具体线段树讲解:(搬运)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;
    }
    

      

  • 相关阅读:
    动态规划记录 [动态更新]
    C++ STL map使用的注意事项记录
    20192425 2021202220192425 《网络与系统攻防技术》实验六实验报告
    20192425 202120222 《网络与系统攻防技术》实验五实验报告
    判断数据的增减
    还有多久退休
    按地名找所属市
    多表汇总
    优秀的编码实践
    client go 架构
  • 原文地址:https://www.cnblogs.com/widerg/p/7345263.html
Copyright © 2020-2023  润新知