由于我不会线段树,先弄一份模板。
基础线段树(闭区间)(单点修改、单点查询):
const int MAXM=50000; //定义 MAXM 为线段最大长度
int a[MAXM+5],st[(MAXM<<2)+5]; // a 数组为 main 函数中读入的内容,st 数组为需要查询的数的信息(如和、最值等),树的空间大小为线段最大长度的四倍
//建树
void build(int o,int l,int r){ //传入的参数为 o:当前需要建立的结点;l:当前需要建立的左端点;r:当前需要建立的右端点
if(l==r)st[o]=a[l]; //当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
else{
int m=l+((r-l)>>1); // m 为中间点,左儿子结点为 [l,m] ,右儿子结点为 [m+1,r];
build(o<<1,l,m); //构建左儿子结点
build((o<<1)|1,m+1,r); //构建右儿子结点
st[o]=st[o<<1]+st[(o<<1)|1]; //递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
}
}
//在 main 函数中的语句 build(1,1,n);
//单点修改
void update(int o,int l,int r,int ind,int ans){ //o、l、r为当前更新到的结点、左右端点,ind为需要修改的叶子结点左端点,ans为需要修改成的值;
if(l==r){ //若当前更新点的左右端点相等即到叶子结点时,直接更新信息并返回
st[o]=ans;
return;
}
int m=l+((r-l)>>1);
if(ind<=m){ //若需要更新的叶子结点在当前结点的左儿子结点的范围内,则递归更新左儿子结点,否则更新右儿子结点
update(o<<1,l,m,ind,ans);
}
else{
update((o<<1)|1,m+1,r,ind,ans);
}
st[o]=max(st[o<<1],st[(o<<1)|1]);//递归回之后用儿子结点更新父节点(此处是区间最大值)
}
//在main函数中的语句 update(1,1,n,ind,ans);
//对应单点修改的单点查询
int query(int o,int l,int r,int ql,int qr){ //ql、qr为需要查询的区间左右端点
if(ql>r||qr<l) return -1; //若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值(如求和时返回0,求最大值时返回-1等)
if(ql<=l&&qr>=r) return st[o]; //若当前结点的区间被需要查询的区间覆盖,则返回当前结点的信息
int m=l+((r-l)>>1);
int p1=query(o<<1,l,m,ql,qr),p2=query((o<<1)|1,m+1,r,ql,qr); //p1为查询左儿子结点得到的信息,p2为查询右儿子结点得到的信息
return max(p1,p2); //综合两个儿子结点的信息并返回
}
//main函数中的语句 printf("%d\n",query(1,1,n,a,b));
整理压行版基础线段树(闭区间):
const int MAXM=50000; //MAXM 为线段最大长度
int a[MAXM+5],st[(MAXM<<2)+5]; //a数组为原数组,st数组为四倍大小线段树
//求和
int op_init=0;
inline int op_cal(int o1,int o2){
return o1+o2;
};
void build(int o,int l,int r) { //o当前结点,l左端点,r右端点,build(1,1,n)
if(l==r) st[o]=a[l];
else {
int m=l+((r-l)>>1);
build(o<<1,l,m);
build((o<<1)|1,m+1,r);
st[o]=op_cal(st[o<<1],st[(o<<1)|1]); //子结点建立完成后,更新父节点
}
}
//单点修改
void update(int o,int l,int r,int ind,int ans){ //ind为叶结点,ans为值,update(1,1,n,ind,ans);
if(l==r){
st[o]=ans;
}
else{
int m=l+((r-l)>>1);
if(ind<=m) update(o<<1,l,m,ind,ans);
else update((o<<1)|1,m+1,r,ind,ans);
st[o]=max(st[o<<1],st[(o<<1)|1]); //子节点更新后,更新父节点
}
}
//对应单点修改的单点查询
int query(int o,int l,int r,int ql,int qr){ //ql、qr为查询区间左右端点,query(1,1,n,a,b)
if(ql>r||qr<l) return op_init; //区间不相交,返回无关值
if(ql<=l&&qr>=r) return st[o]; //若当前区间被查询区间覆盖,返回当前信息
int m=l+((r-l)>>1);
int p1=query(o<<1,l,m,ql,qr); //查询左右子结点信息
int p2=query((o<<1)|1,m+1,r,ql,qr);
return op_cal(p1,p2); //综合子结点的信息返回
}
A 敌兵布阵
//https://vjudge.net/contest/66989#problem/A
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXM=50000; //MAXM 为线段最大长度
int a[MAXM+5],st[(MAXM<<2)+5]; //a数组为原数组st数组为四倍大小线段树
struct SegmentTree{
int n; //线段树的大小
//求和
int op_init=0;
inline int op_cal(int o1,int o2){
return o1+o2;
};
void _build(int o,int l,int r) { //o当前结点,l左端点,r右端点,_build(1,1,n)
if(l==r) {st[o]=a[l];return;}
int m=l+((r-l)>>1);
_build(o<<1,l,m);
_build((o<<1)|1,m+1,r);
st[o]=op_cal(st[o<<1],st[(o<<1)|1]); //子结点建立完成后,更新父节点
}
//单点修改
void _update(int o,int l,int r,int ind,int ans){ //ind为叶结点,ans为值,_update(1,1,n,ind,ans);
if(l==r) {st[o]=ans;return;}
int m=l+((r-l)>>1);
if(ind<=m) _update(o<<1,l,m,ind,ans);
else _update((o<<1)|1,m+1,r,ind,ans);
st[o]=op_cal(st[o<<1],st[(o<<1)|1]); //子节点更新后,更新父节点
}
//对应单点修改的单点查询
int _query(int o,int l,int r,int ql,int qr){ //ql、qr为查询区间左右端点,_query(1,1,n,a,b)
if(ql>r||qr<l) return op_init; //区间不相交,返回无关值
if(ql<=l&&qr>=r) return st[o]; //若当前区间被查询区间覆盖,返回当前信息
int m=l+((r-l)>>1); //综合子结点的信息返回
return op_cal(_query(o<<1,l,m,ql,qr),_query((o<<1)|1,m+1,r,ql,qr));
}
void build(int tn){
n=tn;
_build(1,1,n);
}
void update(int ind,int ans){
_update(1,1,n,ind,ans);
}
int query(int l,int r){
return _query(1,1,n,l,r);
}
};
int main(){
int T;
while(~scanf("%d",&T)){
for(int t=1;t<=T;t++){
printf("Case %d:\n",t);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
SegmentTree st;
st.build(n);
char ins[10];
while(1){
scanf("%s",ins);
if(ins[0]=='E')
break;
int i,j;
scanf("%d%d",&i,&j);
if(ins[0]=='A'){
a[i]+=j;
st.update(i,a[i]);
}
else if(ins[0]=='S'){
a[i]-=j;
st.update(i,a[i]);
}
else if(ins[0]=='Q'){
printf("%d\n",st.query(i,j));
}
}
}
}
}