线段树(1)之单点更新(基础题)

  在代码前先介绍一些我的线段树风格
  • MAX是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于MAX的最小2x的两倍
  • l和r分别表示某个区间的最左与最右的点,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示,mid表示区间中间的(我比较喜欢定义一个mid,也可以不用定义,只是每次要去算mid=(l+r)/2)
  • 点以前的写法是另外开两个个数组记录每个结点所表示的区间,其实这个区间不必保存,一边算一边传下去就行,只需要写函数的时候多两个参数,结合l和r的预定义可以很方便
  • PushUP(int i)是把当前结点的信息更新到父结点,及向上更新
  • PushDown(int i)是把当前结点的信息更新给儿子结点及向下更新
  • i就是当前所在的结点。                                                 
  • (1)单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int i)这个函数更新上来:废话不多说,直接上干粮,这道题是我做的第一道线段树:(hdu 1166)

Description

Lily 特别喜欢养花,但是由于她的花特别多,所以照料这些花就变得不太容易。她把她的花依次排成一行,每盆花都有一个美观值。如果Lily把某盆花照料的好的话,这盆花的美观值就会上升,如果照料的不好的话,这盆花的美观值就会下降。有时,Lily想知道某段连续的花的美观值之和是多少,但是,Lily的算术不是很好,你能快速地告诉她结果吗?

Input

	第一行一个整数T,表示有T组测试数据。
每组测试数据的第一行为一个正整数N(N<=50000),表示Lily有N盆花。接下来有N个正整数,第i个正整数ai表示第i盆花的初始美观值(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1)Add i j, i和j为正整数,表示第i盆花被照料的好,美观值增加j(j<=30)
(2)Sub i j, i和j为正整数,表示第i盆花被照料的不好,美观值减少j(j<=30)
(3)Query i j, i和j为正整数,i<=j,表示询问第i盆花到第j盆花的美观值之和
(4)End,表示结束,这条命令在每组数据最后出现
每组数据的命令不超过40000条
 
     

Output

	对于第i组数据,首先输出"Case i:"和回车。
对于每个"Query i j"命令,输出第i盆花到第j盆花的美观值之和。

Sample Input

1 9
7 9 8 4 4 5 4 2 7
Query 7 9
Add 4 9
Query 3 6
Sub 9 6
Sub 3 3
Query 1 9
End
 
     

Sample Output

Case 1: 133050     看了前面一页博客后,看到题中40000和50000这两个数据之后,果断线段树,原理就是上一页博客说的最基本的点更新原理,每个结构体数组要存某个区间的花的美观值之和,晓得这个之后,就是套路了,直接上代码:
#include #include #define MAX 50000 struct node { int l,r; int mid; int sum; }; node a[MAX*4]; void BuildTree(int i,int l,int r) //建立线段树 { a[i].l=l; a[i].r=r; if(l==r) { scanf("%d",&a[i].sum); return; } a[i].mid=(l+r)/2; BuildTree(i*2,l,a[i].mid); BuildTree(i*2+1,a[i].mid+1,r); a[i].sum=a[i*2].sum+a[i*2+1].sum; //这其实就是我说的那个PushUp(向上更新),这题较简单,向上更新只需要一个语句即可实现,所以就没再写个PushUp函数了 } void update(int i,int index,int num) //点更新 { if(a[i].l==a[i].r) { a[i].sum+=num; return; } if(a[i].mid>=index)update(i*2,index,num); if(a[i].mida[i].mid)return Query(i*2+1,l,r); else return Query(i*2,l,a[i].mid)+Query(i*2+1,a[i].mid+1,r); } int main() { int t,n,i,j; int a,b; int count=0; scanf("%d",&t); while(t--) { count++; char str[10]; scanf("%d",&n); BuildTree(1,1,n); //建立线段树 printf("Case %d:\n",count); while(1) { scanf("%s",str); if(strcmp(str,"Add")==0) { scanf("%d%d",&a,&b); update(1,a,b); } else if(strcmp(str,"Sub")==0) { scanf("%d%d",&a,&b); update(1,a,-b); //利用b与-b控制 美观值的增或者减 } else if(strcmp(str,"Query")==0) { scanf("%d%d",&a,&b); printf("%d\n",Query(1,a,b)); } else break; } } return 0; }
    这只是最基础的线段树,后面的博客会更新各种变化的线段树等。

你可能感兴趣的:(【线段树】)