线段树求和
线段树如下图所示,是一个二叉搜索树,记录了a到b的一些信息,比如在这里我们记录a到b所有节点数的总和。下图所示:根节点是1-4,这个节点可以分为1-2,3-4两个子节点,同理,子节点继续往下面分裂。
例题:
在示例代码中,
1.a数组存放这个线段树,每个节点的父节点(加)或它前面的兄弟节点(减,有时候找不到,直接找到0,就是没有)可以通过lowbit计算
具体展开关系:1->2;2->4;3->4;4->8;5->6;6->8;7->8;
2.lowbit:
正数与它的负数的与,负数的二进制是正数取反再加一
3.getsum
获取0-t的总和,8(4)记录了0-8的所有值,所以直接可求
7:记录了自己,所以要计算6(记录了5-6),4(0-4)
4.代码贴在这主要为了遇到的时候快速复制粘贴
#include <stdio.h> #include <string.h> #include<math.h> int a[50005]; int n; int lowbit(int t){ return t&(-t); } void insert(int t,int d){ while(t<=n){ a[t]+=d; t=t+lowbit(t); } } __int64 getsum(int t){ __int64 sum=0; while(t>0){ sum+=a[t]; t=t-lowbit(t); } return sum; } int main(){ int T,i,j,k,t; scanf("%d",&T); t=0; while(T--){ memset(a,0,sizeof(a)); scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&k); insert(i,k); } char str[10]; scanf("%s",str); printf("Case %d:\n",++t); while(strcmp(str,"End")!=0){ int x,y; scanf("%d%d",&x,&y); if(strcmp(str,"Query")==0) printf("%lld\n",getsum(y)-getsum(x-1)); else if(strcmp(str,"Add")==0) insert(x,y); else if(strcmp(str,"Sub")==0) insert(x,-y); scanf("%s",str); } } return 0; }