HDU 1166
这是一道线段树的入门题,用于学习基本的线段树的建树、更新、访问的操作。只在这里说说基本的操作。
首先是建树(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<stdio.h> #include<stdlib.h> #include<string.h> #define MAX_CAMP 50005 #define MAX_LINE 115 char *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<n;j++) { int tem; scanf("%d",&tem); fix(1,j+1,j+1,tem); } char inpt[MAX_LINE]; printf("Case %d:\n",i); while(scanf("%s",inpt)!=EOF) { if(strcmp(inpt,end)==0) { break; } else if(strcmp(inpt,query)==0) { int le,ri; sum=0; scanf("%d%d",&le,&ri); sum=query_sum(1,le,ri); printf("%d\n",sum); } else if(strcmp(inpt,add)==0) { int dest,num; scanf("%d%d",&dest,&num); fix(1,dest,dest,num); } else { int dest,num; scanf("%d%d",&dest,&num); fix(1,dest,dest,-num); } } } return 0; } void build(int root,int le,int ri) { if(le>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].left) { return ; } fix(root*2,le,ri,val); fix(root*2+1,le,ri,val); camp[root].val=camp[root*2].val+camp[root*2+1].val; } int query_sum(int root,int le,int ri) { if(le<=camp[root].left&&ri>=camp[root].right) { return camp[root].val; } if(le>camp[root].right||ri<camp[root].left) { return 0; } return query_sum(root*2,le,ri)+query_sum(root*2+1,le,ri); }