线段树就是许多线段组成的,并对每条线段进行操作,线段树的节点满足二叉树,所以某个节点的左右儿子是 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;
}
3204

被折叠的 条评论
为什么被折叠?



