算法训练-线段树

WIKIOI-1080 线段树练习

题目描述 Description
一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;

修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数

m<10000条。

输入描述 Input Description
输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数

表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示

要求[a,b]之间的区间和。

输出描述 Output Description
共m行,每个整数

样例输入 Sample Input
6
4 5 6 2 1 3
4
1 3 5
2 1 4
1 1 9
2 2 6
样例输出 Sample Output
22
22
数据范围及提示 Data Size & Hint
1≤N≤100000, m≤10000 。

 

 

 

 

本题的目的是训练线段树的构造
AC代码:

#include<stdio.h>
#include<string.h>
struct node//构造线段树需要的结构体
{
   int l,r;
   int sum;
}a[400010];//线段树需要开2*N以上的空间,此处最容易出错!!
void Bulid(int n,int l,int r)//创建一颗范围为[l,r]的线段树
{
     a[n].l=l;//左边界赋值
     a[n].r=r;//右边界赋值
     a[n].sum=0;//总和初始化
     if(l==r)//如果左右孩子相等,创建结束
     return;
     Bulid(2*n,l,(l+r)/2);//创建左孩子
     Bulid(2*n+1,(l+r)/2+1,r);//创建右孩子
}
void Insert(int n,int v,int num)//向线段树插入位置为v的权值num
{
     a[n].sum+=num;//更新总和
     if(a[n].l==a[n].r)//若左右边界相等,结束更新
     return;
     if(v<=(a[n].l+a[n].r)/2)//位置小于中间值,往左子树插入,反之去右子树
     Insert(n*2,v,num);
     else
     Insert(n*2+1,v,num);
}
void Change(int n,int v,int num)//改变线段树中位置为v的权值(加上num)
{
     if(v==a[n].l&&v==a[n].r)//左右子树相同,执行更新
     {
        a[n].sum+=num;
        return;
     }
     else
     if(v<=(a[n].l+a[n].r)/2)//位置小于中间值,往左子树更新,反之去右子树
     Change(n*2,v,num);
     else
     Change(n*2+1,v,num);
     a[n].sum=a[n*2].sum+a[n*2+1].sum;//由于上面的递归已经修改了权值,更新总值
}
int Sum(int n,int l,int r)//计算位置范围在l、r内数权值的总和
{
     if(l==a[n].l&&r==a[n].r)//边界等于左右子树,输出本位置的权值和
     return a[n].sum;
     if(r<=(a[n].l+a[n].r)/2)//右边界小于中间值,往左子树寻找总和
     return Sum(n*2,l,r);
     else
     if(l>(a[n].l+a[n].r)/2)//左边界大于中间值,往右子树寻找总和
     return Sum(n*2+1,l,r);
     else//不满足上面两个条件,i、r则在 a[n].l与a[n].r中间,那么分别求和
     return Sum(n*2,l,(a[n].l+a[n].r)/2)+Sum(n*2+1,(a[n].l+a[n].r)/2+1,r);

}
int main()
{
    int i,j,n,m,Q,L,R;
    scanf("%d",&n);
    Bulid(1,1,n);
    for(i=1;i<=n;i++)
    {
       scanf("%d",&m);
       Insert(1,i,m);
    }
    scanf("%d",&m);
    while(m--)
    {
       scanf("%d %d %d",&Q,&L,&R);
       if(Q==1)
       {
          Change(1,L,R);
       }
       else if(Q==2)
       {
          printf("%d\n",Sum(1,L,R));
       }
    }
    return 0;
}

本代码为原创,转载请注明出处!

时间: 2024-09-19 09:59:20

算法训练-线段树的相关文章

[算法系列之二十三]线段树(Interval Tree)

一 背景 在信息学竞赛中,我们经常会碰到一些跟区间有关的问题,比如给一些区 间线段求并区间的长度,或者并区间的个数等等.这些问题的描述都非常简单,但是通常情况下数据范围会非常大,而朴素方法的时间复杂度过高,导致不能在规定时间内得到问题的解.这时,我们需要一种高效的数据结构来处理这样的问题,在本文中,我们介绍一种基于分治思想的数据结构--线段树. 二 简介 线段树是一种二叉树形结构,属于平衡树的一种.它将线段区间组织成树形的结构,并用每个节点来表示一条线段.一棵[1,10)的线段树的结构如图1.1

经典算法题每日演练——第十二题 线段树

       这一篇我们来看树状数组的加强版线段树,树状数组能玩的线段树一样可以玩,而且能玩的更好,他们在区间求和,最大,平均 等经典的RMQ问题上有着对数时间的优越表现. 一:线段树      线段树又称"区间树",在每个节点上保存一个区间,当然区间的划分采用折半的思想,叶子节点只保存一个值,也叫单元节点,所 以最终的构造就是一个平衡的二叉树,拥有CURD的O(lgN)的时间. 从图中我们可以清楚的看到[0-10]被划分成线段的在树中的分布情况,针对区间[0-N],最多有2N个节点,

蓝桥杯-算法训练 操作格子

算法训练 操作格子   时间限制:1.0s   内存限制:256.0MB        问题描述 有n个格子,从左到右放成一排,编号为1-n. 共有m次操作,有3种操作类型: 1.修改一个格子的权值, 2.求连续一段格子权值和, 3.求连续一段格子的最大值. 对于每个2.3操作输出你所求出的结果. 输入格式 第一行2个整数n,m. 接下来一行n个整数表示n个格子的初始权值. 接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权

蓝桥杯 算法训练 安慰奶牛

 算法训练 安慰奶牛   时间限制:1.0s   内存限制:256.0M 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是一个奶牛的家.FJ计划除去P条道路中尽可能多的道路,但是还要保持牧场之间 的连通性.你首先要决定那些道路是需要保留的N-1条道路.第j条双向道路连接了牧场Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N; Sj != Ej),而且走完它需要Lj的时

线段树和RMQ解析和模板

这几天在看RMQ的题目,但是很多RMQ的题目也可以用线段树解决... 看来两者之间有很多关系,那就都好好看吧...下面先贴出一个大牛对两者的解释.. RMQ (Range Minimum/Maximum Query)问题是指: 对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在[i,j]里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题  主要方法及复杂度(处理复杂度和查询复杂度)如下:  1.朴素(即搜索) O(n)-O(n)  2.线段树(se

【转】POJ 3264 线段树解法

每个算法都是数学家或者计算机学家多年研究的结果,不是我自己臆造的,所以学习一个新算法的最佳方法还是看写的好的代码. 按照惯例,我就粘贴一个网上写的很好的帖子... 原文地址:http://ip96cns.blog.163.com/blog/static/17009519220112525029459/ 线段树的查找:(感谢高手指点,虽然只是一点却让我把线段树的内容理顺了)这里是我的一些总结吧           一个线段树的结点表示一个区间,同时结点中保存所需要的信息.          如果询

[HDU][线段树]1166.敌兵布阵

Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少

《程序设计解题策略》——1.3 利用线段树解决区间计算问题

1.3 利用线段树解决区间计算问题 在现实生活中,我们经常遇到与区间有关的问题,例如,记录一个区间的最值(最大或最小值)和总量,并在区间的插入.删除.修改中维护这些最值和总量:再如,统计若干矩形并的面积.线段树拥有良好的树形二分特征,我们可以从其定义和结构中发现,在线段树的基础上完成这些问题的计算操作,是十分简捷和高效的.1.3.1 线段树的基本概念 一棵二叉树,记为T(a,b),参数a.b表示该节点表示区间[a,b].区间的长度b-a记为L.递归定义T[a,b]: 若区间长度L>1:区间[a,

[HDU][线段树]1754.I Hate It

思路: 利用线段树实现,具体参考:[算法系列之二十三]线段树(Interval Tree) 代码 /*--------------------------------------------- * 日期:2015-03-24 * 作者:SJF0115 * 题目: 1754.I Hate It * 来源:HDU * 网址:http://acm.hdu.edu.cn/showproblem.php?pid=1754 * 结果:AC * 博客: ----------------------------