线段树是一种数据结构,在查找删除等操作时能节省很多时间,大约为log(n)。但值得注意的是,在建树时所花费的时间比较多,远大于log(n);
做了几道简单的线段树的题目,现在以hdu的1166敌兵布阵为例:
题意:给出一个整型数组a[ ],两种操作:
1.增加(Add)或减少(Sub) a[ i ] 的值;
2.(Query)计算a[ i ] 到 a[ i+k ] 的值(累加和),并输出;
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define max 50005
struct node
{
int r,ldata; //l表示最左端,r表示最右端,data表示数值
};
struct node tree[3*max]; //通常数组开到3*n就够了
int a[2*max];
//1.用指针,但是代码冗长,而且需要注意的细节较多,不建议。
//2.用数组来构造,虽然消耗空间大,但是简单易懂,建议平时都用数组。
void creat(int num,int le,int ri)
{
int mid;
tree[num].l=le; //使父节点的范围为le至ri
tree[num].r=ri;
if(le==ri){
tree[num].data=a[ri];
return ;
}
mid=(le+ri)/2;
creat(num*2,le,mid); //建立左子树
creat(num*2+1,mid+1,ri); //建立右子树
//父节点的data为其左右子树的data之和...此位置语句比较灵活,根据题意设置父节点的data与左右
//子树data的关系..有时可以其最值,有时可以其他情况
tree[num].data=tree[2*num].data+tree[2*num+1].data;
}
//查找,在这到题中以查找到区间时结束,即 le=a[i] to ri=a[i+k]..
//有时可能必须查找到叶子节点才能结束
int search(int num,int le,int ri)
{
int mid;
if(tree[num].l==le&&tree[num].r==ri) //找到时输出data
return tree[num].data;
mid=(tree[num].l+tree[num].r)/2;
if(ri<=mid) //画图判断比较清晰。有三种情况:1.当要查找的区间均在此节点tree[num]的中间偏左时,则找其左子树
return search(2*num,le,ri);
else if(le>mid) //2.当要查找的区间均在此节点tree[num]的中间偏右时,则找其右子树
return search(2*num+1,le,ri);
else //3.当要查找的区间既在此节点tree[num]的中间左右都有时,则找
{
int t1=search(2*num,le,mid); //找左子树从le to mid 这段区间
int t2=search(2*num+1,mid+1,ri); //找右子树从mid+1 to ri 这段区间
return t1+t2; //记得最后要返回其左右子树data之和,因为求的时候一直递归到最后一层,所以要有返回值一直回到最初寻 //找的区间
}
}
void insert(int num,int le,int k) //插入,题目要求单点插入,有时也会有区间插入.插入类似查找,因为必须找到才能更新数值,所以有时可以 //合在一起写
{
int mid;
if(tree[num].l==tree[num].r) //单点插入时,需要找到叶子结点
{
if(tree[num].l==le) //加入叶子结点==要找的a[i],则更新数值
tree[num].data+=k;
return ;
}
mid=(tree[num].l+tree[num].r)/2;
if(le<=mid)
insert(2*num+1,le,k); //由于查找单点,所以只需判断该点位于当前节点tree[num]的mid左或右端即可
//如果查找的时区间,则应该跟查找是判断一样,分三种情况
if(le>=mid)
insert(2*num,le,k);
tree[num].data+=k; //由于是递归,所以不要忘记在每次最后更新值.以便返回父亲节点
}
int main()
{
int t,n,i,b,s,j;
char ch[10];
scanf("%d",&t);
for(j=1;j<=t;j++)
{
// Init();
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
creat(1,1,n);
printf("Case %d:\n",j);
while(scanf("%s",ch)&&strcmp(ch,"End")!=0)
{
scanf("%d%d",&s,&b);
if(strcmp(ch,"Query")==0)
printf("%d\n",search(1,s,b));
if(strcmp(ch,"Add")==0)
insert(1,s,b);
if(strcmp(ch,"Sub")==0)
insert(1,s,-b);
}
}
return 0;
}