传送门1
传送门2
(0)定义:
#define lson rt<<1
#define rson rt<<1|1
const int maxn=1e5+5;//元素总个数
int sum[maxn<<2];//Sum求和,开四倍空间
int a[maxn];//原数组下标[1,n]
(1)建树:
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
void push_up(int rt)//push_up函数更新节点信息,这里是求和
{
sum[rt]=sum[lson]+sum[rson];
}
void build(int l,int r,int rt) //[l,r]表示当前节点区间,rt表示当前节点的实际存储位置
{
if(l==r){//若到达叶节点
sum[rt]=a[l];//存储a数组的值,应该是a[l]
return ;
}
int mid=(l+r)>>1;
//左右递归
build(l,mid,lson);
build(mid+1,r,rson);
//更新信息
push_up(rt);
}
(2)点修改:
假设A[L]+=C
void update(int L,int C,int l,int r,int rt){//[l,r]表示当前区间,rt是当前节点编号//l,r表示当前节点区间,rt表示当前节点编号
if(l==r){//到达叶节点,修改叶节点的值
sum[rt]+=C;
return;
}
int m=(l+r)>>1;
//根据条件判断往左子树调用还是往右
if(L <= m) update(L,C,l,m,lson);
else update(L,C,m+1,r,rson);
push_up(rt);//子节点的信息更新了,所以本节点也要更新信息
}
点修改其实可以写的更简单,只需要把一路经过的Sum都+=C就行了,不过上面的代码更加规范,在题目更加复杂的时候,按照格式写更不容易错。
(3)区间查询(本题为求和):
询问A[L..R]的和
注意到,整个函数的递归过程中,L,R是不变的。
首先如果当前区间[l,r]在[L,R]内部,就直接累加答案
如果左子区间与[L,R]有重叠,就递归左子树,右子树同理。
int query(int L,int R,int l,int r,int rt){//[L,R]表示操作区间,[l,r]表示当前区间,rt:当前节点编号
if(L <= l && r <= R){
//在区间内直接返回
return Sum[rt];
}
int m=(l+r)>>1;
//左子区间:[l,m] 右子区间:[m+1,r] 求和区间:[L,R]
//累加答案
int ans=0;
if(L <= m) ans+=query(L,R,l,m,lson);//左子区间与[L,R]有重叠,递归
if(R > m) ans+=query(L,R,m+1,r,rson); //右子区间与[L,R]有重叠,递归
return ans;
}
下面有两个线段树入门级例题
POJ 3264 Balanced Lineup 求区间的最大值-最小值
rt<<1|1 效果等于 rt<<1+1 ,但是把|换成+后 ,答案就不对了
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
#define mid ((l+r)>>1)//注意最外层别少了括号
#define lson rt<<1
#define rson rt<<1|1
const int maxn=50005;
const int inf=0x3f3f3f3f;
int Max[maxn<<2];//原来的4倍
int Min[maxn<<2];
int ans1,ans2;
void build(int l,int r,int rt)
{
if(l==r){//到了叶节点
scanf("%d",&Max[rt]);
Min[rt]=Max[rt];
}
else{
build(l,mid,lson);
build(mid+1,r,rson);
Max[rt]=max(Max[lson],Max[rson]);
Min[rt]=min(Min[lson],Min[rson]);
}
}
void query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
ans1=max(ans1,Max[rt]);
ans2=min(ans2,Min[rt]);
}
else{
if(L<=mid)
query(L,R,l,mid,lson);
if(R>mid)
query(L,R,mid+1,r,rson);
}
}
int main()
{
int n,m,L,R;
while(cin>>n>>m){
build(1,n,1);
while(m--){
ans1=-inf;
ans2=inf;
scanf("%d%d",&L,&R);
query(L,R,1,n,1);
cout<<ans1-ans2<<endl;
}
}
return 0;
}
HDU 1754 I Hate It单点更新,区间查询最大
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define lson rt<<1
#define rson rt<<1|1
const int maxn=2e5+10;
int tree[maxn<<2];
void push_up(int rt)
{
tree[rt]=max(tree[lson],tree[rson]);
}
void build(int l,int r,int rt)
{
if(l==r){
scanf("%d",&tree[rt]);
return ;
}
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int p,int c,int l,int r,int rt)
{
if(l==r){
tree[rt]=c;//题目是更改一名学生的成绩
return ;
}
if(p<=mid)
update(p,c,l,mid,lson);
else
update(p,c,mid+1,r,rson);
push_up(rt);//上层也要修改
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)//[l,r]是[L,R]的子集
return tree[rt];
int ans=0;
if(L<=mid)
ans=max(ans,query(L,R,l,mid,lson));
if(R>mid)
ans=max(ans,query(L,R,mid+1,r,rson));
return ans;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
build(1,n,1);
while(m--){
char letter;
int a,b;
cin>>letter;
scanf("%d%d",&a,&b);
if(letter=='Q')
cout<<query(a,b,1,n,1)<<endl;
else
update(a,b,1,n,1);
}
}
return 0;
}
#include<iostream>
#include<string.h>
#include<stdio.h>
#define mid ((l+r)>>1)
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn=5e5;
int tree[maxn<<2];
void push_up(int rt)
{
tree[rt]=tree[lson]+tree[rson];
}
void build(int l,int r,int rt)
{
if(l==r){
scanf("%d",&tree[rt]);
return ;
}
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void add(int p,int c,int l,int r,int rt)
{
if(l==r){
tree[rt]+=c;
return ;
}
if(p<=mid){
add(p,c,l,mid,lson);
}
if(p>mid){
add(p,c,mid+1,r,rson);
}
push_up(rt);
}
void sub(int p,int c,int l,int r,int rt)
{
if(l==r){
tree[rt]-=c;
return ;
}
if(p<=mid){
sub(p,c,l,mid,lson);
}
if(p>mid){
sub(p,c,mid+1,r,rson);
}
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
return tree[rt];
}
int ans=0;
if(L<=mid){
ans+=query(L,R,l,mid,lson);
}
if(R>mid){
ans+=query(L,R,mid+1,r,rson);
}
return ans;
}
int main()
{
int T;
cin>>T;
int t=1;
while(T--){
int n;
cin>>n;
int flag = 1;
build(1,n,1);
string s;
cin>>s;
string _end="End";
string _add="Add";
string _query="Query";
string _sub="Sub";
while(s!=_end){
if(flag){
cout<<"Case "<<t++<<":"<<endl;
flag=0;
}
int a,b;
scanf("%d%d",&a,&b);
if(s==_add){
add(a,b,1,n,1);
}
else if(s==_sub){
sub(a,b,1,n,1);
}
else if(s==_query){
cout<<query(a,b,1,n,1)<<endl;
}
cin>>s;
}
}
return 0;
}