官方介绍:
单点更新:
代码主要实现两个功能:1修改、2查询。
修改:
void modify(int p,int l,int r,int x,int v)
{
a[p]+=v;
if(l==r){
return ;
}
int mid=(l+r)/2;
if(mid>=x)modify(p*2,l,mid,x,v);
else modify(p*2+1,mid+1,r,x,v);
}
这是一种写法,也可以用push_up将子结点的信息更新到父亲节点,代码如下 :
void up(int p)
{
a[p]=a[p*2]+a[p*2+1];
}
void modify(int p,int l,int r,int x,int v)
{
if(l==r){
a[p]+=v;
return ;
}
int mid=(l+r)/2;
if(mid>=x)modify(p*2,l,mid,x,v);
else modify(p*2+1,mid+1,r,x,v);
up(p);
}
原先我更偏向第一种写法,但是后来我接触到后面的区间更新之后就改成第二种了,更形象,好理解些。
我也再次注释一下这些参数的意义,以备复习:p:当前的结点、l,r:所查询的区间的起点与终点,会更新、x,v:因为是修改自然少不了要修改的值和修改内容啦,x即为你要改的数,而v就是你要对x的操作内容,默认+。
查询:
int query(int p,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return a[p];//所查询区间为整个区间
int mid=(l+r)/2,res=0;
if(x<=mid) res+=query(p*2,l,mid,x,y);
if(y>mid) res+=query(p*2+1,mid+1,r,x,y);
return res;
}
没什么好说的,就是X,Y 为所查询区间,最后返回的res为所查询区间的内容——这个区间内所有元素之和。
基础知识介绍到这里 来一题模板题:
问题描述
有一种神奇斑点蛇,蛇如其名,全身都是斑点,斑点数量可以任意改变。
有一天,蒜头君十分的无聊,开始数蛇上的斑点。假设这条蛇的长度是N cm,蒜头君已经数完开始时蛇身的第i上有ai个斑点。
现在蒜头君想知道这条斑点蛇的任意区间的蛇身上一共有多少个斑点。这好像是一个很容易的
事情,但是这条蛇好像是和蒜头君过不去,总是刻意的改变蛇身上的斑点数量。
于是,蒜头君受不了了,加上蒜头君有密集型恐惧症。聪明又能干的你能帮帮他吗?
输入格式
第一行一个正整数 N(N≤50000)表示这条斑点蛇长度为 N 厘米,接下来有 N 个正整数,第 i 个正整数 ai 代表第 i 个斑点蛇第 i 厘米开始时有 ai 个斑点(1≤ai≤50)。
接下来每行有一条命令,命令有 4 种形式:
(1) Add i j,i 和 j 为正整数,表示第 i 厘米增加 j 个斑点(j 不超过 30);
(2) Sub i j,i 和 j 为正整数,表示第 i 厘米减少 j 个斑点(j 不超过 30);
(3) Query i j,i 和 j 为正整数,i≤j,表示询问第 i 到第 j 厘米的斑点总数(包括第 i 厘米和第 j 厘米);
(4) End 表示结束,这条命令在每组数据最后出现;
最多有 40000 条命令。
输出格式
对于每个 Query 询问,输出一个整数并回车,表示询问的段中的总斑点数,这个数保证在int范围内。
样例输入
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
样例输出
6
33
59
没什么好说的啊 模板题啊,直接把函数在上面一些就AC了呀
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=50010;
int a[maxn*4+100];
int s[maxn*4+100];
void up(int p)
{
a[p]=a[p*2]+a[p*2+1];
}
void modify(int p,int l,int r,int x,int v)
{
if(l==r){
a[p]+=v;
return ;
}
int mid=(l+r)/2;
if(mid>=x)modify(p*2,l,mid,x,v);
else modify(p*2+1,mid+1,r,x,v);
up(p);
}
int query(int p,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return a[p];
int mid=(l+r)/2,res=0;
if(x<=mid) res+=query(p*2,l,mid,x,y);
if(y>mid) res+=query(p*2+1,mid+1,r,x,y);
return res;
}
int main()
{
int n,d;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&d);
modify(1,1,n,i,d);
}
string s;
while(cin>>s){
if(s=="End")break;
int i,j;
cin>>i>>j;
if(s=="Query") {
int wyh=query(1,1,n,i,j);
printf("%d\n",wyh);
}
if(s=="Add") modify(1,1,n,i,j);
if(s=="Sub") modify(1,1,n,i,-j);
}
return 0;
}
值得一提的是:这线段树类的题目要把数组开到maxn的4倍以上。