一定要做的线段树习题汇总
一、模板
#include
#include
#include
using namespace std;
#define MAXN 200010
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
int sum[MAXN<<2];
void pushUp(int p)
{
sum[p]=max(sum[p<<1],sum[p<<1|1]);
}
void build(int l,int r,int p)
{
if(l==r){
scanf("%d",&sum[p]);
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
pushUp(p);
}
int query(int l,int r,int p,int a,int b)
{
if(l>=a&&b>=r) //根据功能代码修改部分
return sum[p];
int ans=0;
int mid=(l+r)>>1;
if(mid>=a)
ans=max(ans,query(lson,a,b)); //根据功能代码修改部分
if(mid
//根据功能代码修改部分
sum[p]=b; return ; } int mid=(l+r)>>1; if(a<=mid) update(lson,a,b); else update(rson,a,b); pushUp(p);}int main(){ int n,m; char ch[5]; //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { int a,b; build(1,n,1); while(m--) { scanf("%s%d%d",ch,&a,&b); if(ch[0]=='Q') printf("%d\n",query(1,n,1,a,b)); else update(1,n,1,a,b); } } return 0;}
二、区间查询,无单点更新
#include
#include
#include
#include
using namespace std;
const int maxn=200010;
int sum[maxn<<2];//数组开四倍
int h,w,n;
//p表示下标
void pushUp(int p)
{
//p表示下标,赋值为两个儿子中的最大值
sum[p]=max(sum[p<<1],sum[p<<1|1]);
}
//建树
void build(int l,int r,int p)
{
if(l==r)//区间长度为0时结束递归
{
sum[p]=w;
return ;
}
//否则的话,分别递归左儿子和右儿子
int mid=(r+l)>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
pushUp(p);
}
//区间查询
//线段树的最高顶点是表示所有行里面最大的宽度
int query(int l,int r,int p,int num)
{
if(l==r)//找到了一个完全重合的区间
{
sum[p]-=num;//进行对应的查询操作
return l;
}
int ans;
int mid=(r+l)>>1;//下面要注意,先保存ans,然后更新值后再返回
if(sum[p<<1]>=num)
{
ans=query(l,mid,p<<1,num);
}
else
{
ans=query(mid+1,r,p<<1|1,num);
}
pushUp(p);
return ans;
}
int main()
{
while(scanf("%d%d%d",&h,&w,&n)!=EOF)
{
memset(sum,0,sizeof(sum));
if(h>n)h=n;
int temp;
build(1,h,1);//建树区间为[1,h],下标开始序号为1
for(int i=0;i
三、单点更新+区间求和
#include
#include
#include
using namespace std;
#define MAXN 50010
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define mem(a) memset(a,0,sizeof(a[0]))
int sum[MAXN<<2];
void pushUp(int p)
{
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void build(int l,int r,int p)
{
if(l==r){
scanf("%d",&sum[p]);
return;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
pushUp(p);
}
int query(int l,int r,int p,int i,int j)
{
if(l>=i&&r<=j){
return sum[p];
}
int ans=0;
int mid=(l+r)>>1;
if(mid=i) ans+=query(lson,i,j);
return ans;
}
void update(int l,int r,int p,int i,int j)
{
if(l==r){
sum[p]+=j;
return ;
}
int mid=(l+r)>>1;
if(mid>=i)
update(lson,i,j);
else
update(rson,i,j);
pushUp(p);
}
int main()
{
int n,T;
int cases=1;
char str[10];
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
mem(sum);
scanf("%d",&n);
printf("Case %d:\n",cases++);
int i,j;
build(1,n,1);
while(scanf("%s",str)&&strcmp(str,"End"))
{
scanf("%d%d",&i,&j);
if(strcmp(str,"Query")==0)
printf("%d\n",query(1,n,1,i,j));
else if(strcmp(str,"Add")==0)
update(1,n,1,i,j);
else if(strcmp(str,"Sub")==0)
update(1,n,1,i,-j);
}
}
return 0;
}
四、区间查询最值+单点更新
#include
#include
#include
using namespace std;
#define MAXN 200010
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
int sum[MAXN<<2];
void pushUp(int p)
{
sum[p]=max(sum[p<<1],sum[p<<1|1]);
}
void build(int l,int r,int p)
{
if(l==r){
scanf("%d",&sum[p]);
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
pushUp(p);
}
int query(int l,int r,int p,int a,int b)
{
if(l>=a&&b>=r)
return sum[p];
int ans=0;
int mid=(l+r)>>1;
if(mid>=a)
ans=max(ans,query(lson,a,b));
if(mid>1;
if(a<=mid) update(lson,a,b);
else update(rson,a,b);
pushUp(p);
}
int main()
{
int n,m;
char ch[5];
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
int a,b;
build(1,n,1);
while(m--)
{
scanf("%s%d%d",ch,&a,&b);
if(ch[0]=='Q')
printf("%d\n",query(1,n,1,a,b));
else
update(1,n,1,a,b);
}
}
return 0;
}