线段树,类似区间树,它在各个节点保留一条线段(数组中的一段子树组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(logn)。线段树的每个节点表示一个区间,子节点则分别表示父节点的左右半区间,例如父亲的区间是[a,b],那么(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b]。
模版
//区间和样例
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int a[maxn];
struct{
int l,r,w;//左边界、右边界、权值
}Tree[maxn<<2];
void pushup(int rt){//向上回溯
Tree[rt].w=Tree[rt<<1].w+Tree[rt<<1|1].w;
}
void build(int rt,int l,int r){//创建
Tree[rt].l=l;Tree[rt].r=r;Tree[rt].w=0;
if(l==r){
Tree[rt].w=a[l];
return ;
}
int mid=(l+r)/2;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int pos,int val){//更新节点
if(Tree[rt].l==Tree[rt].r&&Tree[rt].l==pos){
Tree[rt].w=val;
return ;
}
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(pos<=mid)update(rt<<1,pos,val);
else update(rt<<1|1,pos,val);
pushup(rt);
}
int query(int rt,int l,int r){//查询
if(l<=Tree[rt].l&&Tree[rt].r<=r){
return Tree[rt].w;
}
int mid=(Tree[rt].l+Tree[rt].r)/2;
int ans=0;
if(mid>=l)ans+=query(rt<<1,l,r);
if(mid<r)ans+=query(rt<<l|1,l,r);
return ans;
}
int main(){
return 0;
}
应用
题源:HDU 1754
//求区间最大值
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int a[maxn];
struct{
int l,r,w;
}Tree[maxn<<2];
int max(int a,int b){
return a>b?a:b;
}
void pushup(int rt){
Tree[rt].w=max(Tree[rt<<1].w,Tree[rt<<1|1].w);
}
void build(int rt,int l,int r){
Tree[rt].l=l;Tree[rt].r=r;Tree[rt].w=0;
if(l==r){
Tree[rt].w=a[l];
return ;
}
int mid=(l+r)/2;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int pos,int val){
if(Tree[rt].l==Tree[rt].r&&Tree[rt].l==pos){
Tree[rt].w=val;
return ;
}
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(pos<=mid)update(rt<<1,pos,val);
else update(rt<<1|1,pos,val);
pushup(rt);
}
int query(int rt,int l,int r){
if(l<=Tree[rt].l&&Tree[rt].r<=r){
return Tree[rt].w;
}
int mid=(Tree[rt].l+Tree[rt].r)/2;
int ans=0;
if(mid>=l)ans=query(rt<<1,l,r);
if(mid<r)ans=max(ans,query(rt<<1|1,l,r));
return ans;
}
int main(){
int N,M,A,B;
char cmd[2];
while(~scanf("%d%d",&N,&M)){
for(int i=1;i<=N;i++){
scanf("%d",a+i);
}
build(1,1,N);
for(int i=1;i<=M;i++){
scanf("%s%d%d",cmd,&A,&B);
if(strcmp(cmd,"Q")==0)cout<<query(1,A,B)<<endl;
else if(strcmp(cmd,"U")==0)update(1,A,B);
}
}
return 0;
}