线段树也是处理数组的一个很好的工具,当时和树状数组是同时学的。据说树状数组是可以更简单的解决一些线段树的问题,但是线段树的最经典二叉树结构,比起树状数组的结构简单的多。而且,同样的,处理到区间更新或者区间查询问题,线段树的处理可以说是相当的清晰透彻,而树状数组的要多加函数、多维护数组,只能说是很巧妙,精彩是精彩,用起来也难。
这是做了个简单对比,仅是自己的理解。然后整理出来线段树的模板。是以维护区间最值为例的,单点和区间操作只是小部分的改动,本质上一样的。
单点更新区间查询
#include<cstring>
#include<stdio.h>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX=131100;
struct Tree
{
int l, r;
int minn, maxx;
int f;
}tree[4*MAX];
int a[MAX];
int Min, Max;
void build(int k, int left, int right)
{
tree[k].l=left;
tree[k].r=right;
if(left==right)
{
tree[k].minn=tree[k].maxx=a[left];
return ;
}
int mid=(left+right)/2;
build(2*k, left, mid);
build(2*k+1, mid+1, right);
tree[k].minn=min(tree[2*k].minn, tree[2*k+1].minn);
tree[k].maxx=max(tree[2*k].maxx, tree[2*k+1].maxx);
}
void updatePoint(int k, int pos, int v)
{
if(tree[k].l==tree[k].r)
{
tree[k].minn=tree[k].maxx=v;
return ;
}
int mid=(tree[k].l+tree[k].r)/2;
if(pos<=mid)
updatePoint(k*2, pos, v);
else
updatePoint(k*2+1, pos, v);
tree[k].minn=min(tree[2*k].minn, tree[2*k+1].minn);
tree[k].maxx=max(tree[2*k].maxx, tree[2*k+1].maxx);
}
void queryInterval(int k, int left, int right)
{
if(tree[k].r<left || tree[k].l>right)
return ;
if(tree[k].l>=left && tree[k].r<=right)//再区间里面
{
Min=min(Min, tree[k].minn);
Max=max(Max, tree[k].maxx);
return ;
}
int mid=(tree[k].l+tree[k].r)/2;
if(left<=mid)
queryInterval(2*k, left, right);
if(right>mid)
queryInterval(2*k+1, left, right);
}
int main()
{
int T, N, M;
int ch, x, y;
scanf("%d", &T);
while(T--)
{
LL ans;
scanf("%d", &N);
N=pow(2, N);
for(int i=1; i<=N; i++)
scanf("%d", &a[i]);
build(1, 1, N);
scanf("%d", &M);
for(int i=1; i<=M; i++)
{
scanf("%d%d%d", &ch, &x, &y);
if(ch==1)
{
x++; y++;
Min=1e9;
Max=-1e9;
queryInterval(1, x, y);
if(Max<=0)
ans=(LL)(Max*Max);
if(Min>=0)
ans=(LL)(Min*Min);
if(Min<0 && Max>0)
ans=(LL)(Min*Max);
printf("%lld\n", ans);
}
else
{
x++;
updatePoint(1, x, y);
}
}
}
return 0;
}
区间更新区间查询:
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
#define lson k*2, left, mid
#define rson k*2+1, mid+1, right
const int MAXN =131100;
int MAX[MAXN*4],MIN[MAXN*4];
void pushUpMax(int k)
{
MAX[k]=max(MAX[k*2], MAX[k*2+1]);
}
void pushUpMin(int k)
{
MIN[k]=min(MIN[k*2], MIN[k*2+1]);
}
void build(int k, int left, int right)
{
if(left==right)
{
scanf("%d", &MAX[k]);
MIN[k]=MAX[k];
return ;
}
int mid=(left+right)/2;
build(lson);
build(rson);
pushUpMax(k);
pushUpMin(k);
}
void update(int k, int left, int right, int pos, int v)
{
if(left==right)
{
MIN[k]=MAX[k]=v;
return ;
}
int mid=(left+right)/2;
if(pos<=mid)
update(lson, pos, v);
else
update(rson, pos, v);
pushUpMax(k);
pushUpMin(k);
}
int queryMin(int k, int left, int right, int L, int R)
{
if(left>=L && right<=R)
{
return MIN[k];
}
int mid=(left+right)/2;
int ans=MAXN;
if (L<=mid) ans=min(ans, queryMin(lson, L, R));
if (R>mid) ans=min(ans, queryMin(rson, L, R));
return ans;
}
int queryMax(int k, int left, int right, int L, int R)
{
if(left>=L && right<=R)
{
return MAX[k];
}
int mid=(left+right)/2;
int ans=MAXN;
if (L<=mid) ans=max(ans, queryMax(lson, L, R));
if (R>mid) ans=max(ans, queryMax(rson, L, R));
return ans;
}
int main()
{
int T, n, m;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
n=pow(2, n);
build(1, 1, n);
scanf("%d", &m);
while(m--)
{
int a, b, ch;
scanf("%d%d%d", &ch, &a, &b);
a++;
if(ch==1)
{
b++;
ll t1=(ll)queryMin(1, 1, n, a, b);
ll t2=(ll)queryMax(1, 1, n, a, b);
ll ans;
if(t1<0 && t2>0)
{
ans=t1*t2;
printf("%lld\n",ans);
}
else if(t1>0 || t2<0)
{
ans=min(t2*t2, t1*t1);
printf("%lld\n",ans);
}
}
else update(1, 1, n, a, b);
}
}
return 0;
}