线段树 杭电 1166(入门)

来源:互联网 发布:裁剪照片的软件 编辑:程序博客网 时间:2024/06/05 19:20
参考了一下资料. http://blog.sina.com.cn/s/blog_86fff3d101019kf1.html
首先来说说线段树吧。
从我的理解来看 线段树 其实就是 一颗二叉树 能比较快的对数据进行维护和修改,时间复杂度是 O(log n),可想而知有多快。就如下图:
在[0,n](k=1)的区间上,其 left 叶子结点 是 [0,(0 + n)/2] (k =2*k); 
right 叶子结点 是 [(0 + n)/2 +1,n] (k = 2*k+1); 以此类推。。
下面是代码操作:
1 建树
建树的第一步是定义一个结构体: 
struct tree
{
int left,right,sum; //左右结点  
}a[max * 4]; //a[k] 
然后就到真真的建树的过程了:
void build(int l,int r,int k)  // l表示要求的left结点 ,r 是right结点 ,k 表示的是第几个结构图储存
{
a[k].left = l; //让a[k] 中的左右叶子结点 都有记录。
a[k].right = r;
if(l == r) //相等 即 表示 这已经是在一点上了
{
a[k].sum = num[l];  
return;
}
else  //不相等 就递归建立 子树
{
int mid = (l + r)/2;
build(l,mid,2*k); //建立 a[1,mid]树
build(mid+1,r,2*k +1); //建立 a[mid + 1,r]树
a[k].sum = a[2*k].sum + a[2*k+1].sum; 
}
}

2 操作分为2种
第一种 更新操作:
void update(int k,int index,int change) //k 表示更新哪一个,index表示需要修改的点 
{
a[k].sum += change; //更改某点的值 使区间相应更改
//如果该线段已经是一个点了,结束更改
//否则 将值传递下去
if(a[k].left == a[k].right &&a[k].left==index)
{
return;
}
else 
{
int mid = (a[k].right + a[k].left)/2;
if(index <= mid) // index 在 mid 的left 所以更新left结点的值
update(2*k,index,change);
else //在 right 所以更新 right结点的值。
update(2*k + 1,index,change);
}
}

第二种 查找:
int find(int l,int r,int k) //l,r 为要求的 区间长度,k为 开始
{
int sum = 0;
// 如果 给定的区间包含了 a[k]上的区间 则直接 可以加上去
if(l <= a[k].left&& r >= a[k].right ) 
{
sum = a[k].sum;
}
// 否则 查找该区间涵盖了左右树中的哪些区间
else
{
int mid = (a[k].left + a[k].right)>> 1;
if(mid < r ) //与 right 区间的交集
{
sum =sum + find(l,r,2*k+1);
}
if(l <= mid) //与 left 区间的交集
{
sum =sum + find(l,r,2*k);
}
}
return sum;
}

大功告成 。。。。
至于剩下的就简单了,至于1166 不罗嗦 上代码.
#include<stdio.h>
#define max  50005
int num[50005];
struct tree
{
int left,right,sum;
}a[max * 4];

void build(int l,int r,int k)
{
a[k].left = l;
a[k].right = r;
if(l == r)
{
a[k].sum = num[l];
return;
}
else 
{
int mid = (l + r)/2;
build(l,mid,2*k);
build(mid+1,r,2*k +1);
a[k].sum = a[2*k].sum + a[2*k+1].sum;
}
}
void update(int k,int index,int change)
{
a[k].sum += change;
if(a[k].left == a[k].right &&a[k].left==index)
{
return;
}
else 
{
int mid = (a[k].right + a[k].left)/2;
if(index <= mid)
update(2*k,index,change);
else
update(2*k + 1,index,change);
}
}
int find(int l,int r,int k)
{
int sum = 0;
if(l <= a[k].left&& r >= a[k].right)
{
sum += a[k].sum;
}
else
{
int mid = (a[k].left + a[k].right)>> 1;
if(mid < r )
{
sum =sum + find(l,r,2*k+1);
}
if(l <= mid)
{
sum =sum + find(l,r,2*k);
}
}
return sum;
}
int main()
{
int t;
while(~scanf("%d",&t))
{
for(int h = 1;h <= t;h++)
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&num[i]);
build(1,n,1);
//for(int i = 1;i <= n;i++)
//printf("%d %d %d%d\n",i,a[i].left,a[i].right,a[i].sum);
char op[10];
printf("Case %d:\n",h);
while(~scanf("%s",op) && op[0]!= 'E')
{
//printf("%d %d",x,y);
int x,y;
scanf("%d%d",&x,&y);
if(op[0] == 'Q')
{
printf("%d\n",find(x,y,1));
}
else if(op[0] == 'A')
{
update(1,x,y);
}
else if(op[0] == 'S')
{
update(1,x,-y);
}
}
}
}
}
0 0
原创粉丝点击