线段树就是许多线段组成的,并对每条线段进行操作,线段树的节点满足二叉树,所以某个节点的左右儿子是 2*rt,和2*rt+1;
举例说明:已知线段[2,5] [4,6] [0,7];求点2,4,7分别出现了多少次
在[0,7]区间上建立一棵满二叉树:(为了和已知线段区别,用【】表示线段树中的线段)
【0,7】
/ \
【0,3】 【4,7】
/ \ / \
【0,1】 【2,3】 【4,5】 【6,7】
/ \ / \ / \ / \
【0,0】 【1,1】 【2,2】 【3,3】 【4,4】 【5,5】 【6,6】 【7,7】
三条已知线段插入过程:
[2,5]
--[2,5]与【0,7】比较,分成两部分:[2,3]插到左儿子【0,3】,[4,5]插到右儿子【4,7】
--[2,3]与【0,3】比较,插到右儿子【2,3】;[4,5]和【4,7】比较,插到左儿子【4,5】
--[2,3]与【2,3】匹配,【2,3】记录+1;[4,5]与【4,5】匹配,【4,5】记录+1
[4,6]
--[4,6]与【0,7】比较,插到右儿子【4,7】
--[4,6]与【4,7】比较,分成两部分,[4,5]插到左儿子【4,5】;[6,6]插到右儿子【6,7】
--[4,5]与【4,5】匹配,【4,5】记录+1;[6,6]与【6,7】比较,插到左儿子【6,6】
--[6,6]与【6,6】匹配,【6,6】记录+1
[0,7]
--[0,7]与【0,7】匹配,【0,7】记录+1
插入过程结束,线段树上的记录如下(红色数字为每条线段的记录n):
【0,7】
1
/ \
【0,3】 【4,7】
0 0
/ \ / \
【0,1】 【2,3】 【4,5】 【6,7】
0 1 2 0
/ \ / \ / \ / \
【0,0】 【1,1】 【2,2】 【3,3】 【4,4】 【5,5】 【6,6】 【7,7】
0 0 0 0 0 0 1 0
询问操作和插入操作类似,也是递归过程,略
2——依次把【0,7】 【0,3】 【2,3】 【2,2】的记录n加起来,结果为2
4——依次把【0,7】 【4,7】 【4,5】 【4,4】的记录n加起来,结果为3
7——依次把【0,7】 【4,7】 【6,7】 【7,7】的记录n加起来,结果为1
练习: http://acm.nyist.net/JudgeOnline/code.php?runid=260199 士兵杀敌三。
#include<stdio.h>
#include<string.h> #define maxn 4000002 int sum=0; struct tree { int left,right,n; int mid() { return (left+right)>>1; } }; tree a[maxn]; void buildtree(int s,int t,int n) { a[n].left=s; a[n].right=t; int mid=a[n].mid(); if(s==t) return ; buildtree(s,mid,2*n); buildtree(mid+1,t,2*n+1); } void insert(int s,int t,int step,int h)//插入: { if(s==a[step].left&&t==a[step].right) { a[step].n+=h; return ; } if(a[step].left==a[step].right) return ;//当前线段没有儿子,插入结束; int mid=a[step].mid(); if(mid>=t) insert(s,t,step*2,h);//如果中点在T的右边,插到左儿子 else if(mid<s) insert(s,t,step*2+1,h);//在S的左边,插到右儿子。 else//否则,中点在ST中间,各分到左右儿子里。 { insert(s,mid,step*2,h); insert(mid+1,t,step*2+1,h); } } void count(int s,int t,int step)//访问 { if(a[step].n!=0) sum+=a[step].n; if(a[step].left==a[step].right) return; int mid=a[step].mid(); if(mid>=t) count(s,t,step*2); else if(mid<s) count(s,t,step*2+1); else { count(s,mid,step*2); count(mid+1,t,step*2+1); } } int main() { int m,b,c,i,t,h; char ss[6]; while(~scanf("%d%d",&c,&m)) { for(i=0;i<=m;i++) a[i].n=0; buildtree(1,m,1); while(c--) { scanf(" %s",ss); if(strcmp(ss,"ADD")==0) { scanf("%d%d%d",&b,&t,&h); insert(b,t,1,h); } if(strcmp(ss,"QUERY")==0) { sum=0; scanf("%d",&t); count(t,t,1); printf("%d\n",sum); } } } return 0; }