题意:给你n个点,告诉你每个点的值,然后有四种询问:增加其中一个点的值,增加其中一个点值,求一个区间的和,还有一个就是代表结束。
条件:1 单点更新
2 区间求和
思路:简单的线段树基本操作
扩展:
线段树:它将每个区间划分成一些简单的区间,每个区间对应线段树中的一个节点。对于线段树中每一个非叶子节点[a,b],它的左子树区间表示为[a,(a+b)/2],右子树的区间表示为[(a+b)/2,b]。树为平衡二叉树,最后子节点数目为n。
作用:主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(logn)。
结合这题来理解:
(1)线段树的储存:用数组来存储,数组的大小一般开为总数的4倍。因为未优化的空间复杂度为2n但是为了防止数组越界一般会开4倍,有时会通过离散化来优化。
(2)线段树的建立:知道了大小遍历线段树,然后叶子节点的区间和就等于对应数字,最后递归完叶子,再让父节点等于叶子节点的和。
(3)线段树的单点修改:遍历递归到对应的单点然后进行修改,最后递归完叶子,再让父节点等于叶子节点的和。(这里递归到子叶要进行剪枝,就是范围判断一下)
(4)线段树的区间输出:递归同时进行范围的剪枝,然后递归到包含有的区间求和输出就好了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=50001;
int sum_tree[maxn<<2];
int array_tree[maxn];
void build_tree(int node,int fst,int lst)//线段树的建立
{
if(fst==lst)//递归到子叶
{
sum_tree[node]=array_tree[fst];//子叶的区间和等于其本身
return ;
}
int mid=(fst+lst)/2;
build_tree(2*node,fst,mid);//左子树
build_tree(2*node+1,mid+1,lst);//右子数
sum_tree[node]=sum_tree[2*node+1]+sum_tree[2*node];//递归完左右,父节点等于其和
}
void updata_tree(int node,int fst,int lst,int val,int add)//单点修改
{
if(fst==lst)//递归到单点
{
sum_tree[node]+=add;//单点修改
return ;
}
int mid=(fst+lst)/2;
if(val<=mid)//范围的剪枝
updata_tree(node*2,fst,mid,val,add);
else
updata_tree(node*2+1,mid+1,lst,val,add);
sum_tree[node]=sum_tree[node*2]+sum_tree[node*2+1];//递归完左右,父节点等于其和
}
int query_tree(int node,int fst,int lst,int val_fst,int val_lst)//区间的查找
{
if(val_fst>lst||val_lst<fst) return 0;//如果范围不符合规范
if(val_fst<=fst&&val_lst>=lst)//如果包含了这个范围
return sum_tree[node];
int ans=0;
int mid=(fst+lst)/2;
ans+=query_tree(node*2,fst,mid,val_fst,val_lst);
ans+=query_tree(node*2+1,mid+1,lst,val_fst,val_lst);
return ans;
}
int main()
{
int t;
scanf("%d",&t);
int t1=0;
while(t--)
{
printf("Case %d:\n",++t1);
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&array_tree[i]);
build_tree(1,0,n-1);
while(1)
{
string s;
int i,j;
cin>>s;
if(s=="Add")
{
cin>>i>>j;
updata_tree(1,0,n-1,i-1,j);
}
else if(s=="Sub")
{
cin>>i>>j;
updata_tree(1,0,n-1,i-1,-j);
}
else if(s=="Query")
{
cin>>i>>j;
printf("%d\n",query_tree(1,0,n-1,i-1,j-1));
}
else if(s=="End")
break;
}
}
return 0;
}
寄语:1 加油,现在开始一个专题一个专题的攻略,争取暑假有进步