处理何种问题:数组单点更新,单点查询,区间更新,区间求和,区间求最值。
性能:时间复杂度为O(logn)
原理:区间跟新的懒惰标记了解一下,其余略
实现步骤:略
备注:在线段树里,单点更新与单点累加和树状数组上的单点跟新有区别,树状数组还需与原数组求差值,线段树不用。
线段树的区间求最值差别不大,在此贴一份A过题的最值代码,用来对比找bug。
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
const int MaxN=200010;
struct node
{
int l,r,w;
};
node tree[MaxN*4];
int num[MaxN];
int n,ctor,x,ans,a,b,y;
void built(int k,int ll,int rr)
{
tree[k].l=ll;
tree[k].r=rr;
if(tree[k].l==tree[k].r)
{
tree[k].w=num[ctor++];
}
else
{
int m=(ll+rr)/2;
built(k*2,ll,m);
built(k*2+1,m+1,rr);
tree[k].w=max(tree[k*2].w,tree[k*2+1].w);
}
}
void change_point(int k)
{
if(tree[k].l==tree[k].r)
{
tree[k].w=y;
}
else
{
int m=(tree[k].l+tree[k].r)/2;
if(x<=m)
change_point(k*2);
else
change_point(k*2+1);
tree[k].w=max(tree[k*2].w,tree[k*2+1].w);
}
}
void ask_interval(int k)
{
if(a<=tree[k].l&&tree[k].r<=b)
{
ans=max(ans,tree[k].w);
}
else
{
int m=(tree[k].l+tree[k].r)/2;
if(a<=m)
ask_interval(k*2);
if(b>m)
ask_interval(k*2+1);
}
}
int main()
{
int m;
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;++i) scanf("%d",&num[i]);
ctor=1;
built(1,1,n);
while(m--)
{
char c;
getchar();
scanf("%c",&c);
if(c=='Q')//查询
{
scanf("%d%d",&a,&b);
ans=-100;
ask_interval(1);
printf("%d\n",ans);
}
else if(c=='U')//单点更新
{
scanf("%d%d",&x,&y);
change_point(1);
}
}
}
return 0;
}
输入样例解释:
9//n个元素
1 2 3 4 5 6 7 8 9
1 5//单点查询为1,x为坐标,从1开始计数
2 5 0//单点修改为2,x为坐标,y为更新值,
3 1 5//区间查询为3,查询[a,b]区间内的元素和,
4 1 5 10//区间更新为4,将[a,b]区间内的元素均加y
输出样例解释:
5 //对于1的操作
10//对于3的操作输出
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
const int MaxN=100010;
struct node
{
int l,r,w,f;//左边界,右边界,值,懒惰标记
};
node tree[MaxN*4];
int num[MaxN];//原序列
int n,ctor,x,ans,a,b,y;//元素个数,建树是计数变量,单点查询时位置,左区间,右区间,区间修改值
void built(int k,int ll,int rr)//建树
{
tree[k].l=ll;
tree[k].r=rr;
if(tree[k].l==tree[k].r)
{
tree[k].w=num[ctor++];
}
else
{
int m=(ll+rr)/2;
built(k*2,ll,m);
built(k*2+1,m+1,rr);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
}
void down(int k)//懒惰标记
{
tree[k*2].f+=tree[k].f;
tree[k*2+1].f+=tree[k].f;
tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
tree[k].f=0;
}
void ask_point(int k)//单点查询
{
if(tree[k].l==tree[k].r)
{
ans=tree[k].w;
}
else
{
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(x<=m)
ask_point(k*2);
else
ask_point(k*2+1);
}
}
void change_point(int k)//单点更新
{
if(tree[k].l==tree[k].r)
{
tree[k].w+=y;
}
else
{
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(x<=m)
change_point(k*2);
else
change_point(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
}
void ask_interval(int k)//区间查询
{
if(a<=tree[k].l&&tree[k].r<=b)
{
ans+=tree[k].w;
}
else
{
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(a<=m)
ask_interval(k*2);
if(b>m)
ask_interval(k*2+1);
}
}
void change_interval(int k)//区间更新
{
if(a<=tree[k].l&&tree[k].r<=b)
{
tree[k].w+=(tree[k].r-tree[k].l+1)*y;
tree[k].f+=y;
}
else
{
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(a<=m)
change_interval(k*2);
if(b>m)
change_interval(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
}
int main()
{
while(~scanf("%d",&n))//n 为元素个数
{
for(int i=1; i<=n; ++i) scanf("%d",&num[i]);
ctor=1;
built(1,1,n);
int m;//操作次数
scanf("%d",&m);
while(m--)
{
int Q;
scanf("%d",&Q);
ans=0;
if(Q==1)//单点查询
{
scanf("%d",&x);
ask_point(1);
printf("%d\n",ans);
}
else if(Q==2)//单点更新
{
scanf("%d%d",&x,&y);
change_point(1);
}
else if(Q==3)//区间查询
{
scanf("%d%d",&a,&b);
ask_interval(1);
printf("%d\n",ans);
}
else if(Q==4)//区间更新
{
scanf("%d%d%d",&a,&b,&y);
change_interval(1);
}
}
}
return 0;
}