这是一道线段树的入门题,用于学习基本的线段树的建树、更新、访问的操作。只在这里说说基本的操作。
首先是建树(void build(int root,int le,int ri)),采用递归的方式:root为当前节点,le为区间的左端点,ri为区间的右端点;如果le==ri,说明此时长度为1,建到最底层了,所以返回;否则,建立左子树和右子树,显然左子树在数组中的下标为2*root,右子树为2*root+1,这时还要将区间一分为二,左子树负责[le,(le+ri)/2]的部分,右子树负责[(le+ri)/2+1,ri]的部分。另外一个操作是更新(void fix(int root,int le,int ri,int val)),同样采用递归的方式,当le>camp[root].right或ri<camp[root].left,说明当前节点负责的区间不是需要更新的区间,返回。显然只有当le<=camp[root].left且ri>=camp[root].right的时候当前节点负责的区间才是需要更新区间的子集,于是更新当前节点,然后更新其左子树和右子树。访问操作因题而异,这道题里如果当前区间是需要查询区间的子集,就返回节点存储的val。
#include#include #include #define MAX_CAMP 50005#define MAX_LINE 115char *query="Query",*add="Add",*sub="Sub",*end="End";struct segTree{ int left; int right; int val;}camp[4*MAX_CAMP];void build(int,int,int),fix(int,int,int,int);int query_sum(int,int,int),sum=0,n;int main(){ int t,i; scanf("%d",&t); for(i=1;i<=t;i++) { int j; scanf("%d",&n); memset(camp,0,sizeof(camp)); build(1,1,n); for(j=0;j ri) return ; camp[root].left=le; camp[root].right=ri; if(le==ri) return ; int mid=(ri+le)/2; build(root*2,le,mid); build(root*2+1,mid+1,ri);}void fix(int root,int le,int ri,int val){ if(le<=camp[root].left&&ri>=camp[root].right) { camp[root].val+=val; return ; } if(le>camp[root].right||ri =camp[root].right) { return camp[root].val; } if(le>camp[root].right||ri