线段树之区间求和 POJ 3468 线段树入门

来源:互联网 发布:淘宝被骗怎么退款 编辑:程序博客网 时间:2024/06/05 17:59

题目就是要经常查询某短区间的和,而且要经常修改一段区间的值即同是把这个区间的每个元素都加上一数

这中要求线段树就可以实现修改和查询的时间都是logN的

下面是代码,注释可以参考一下,希望可以解释清楚,第一次学可能不好懂,但出几个简单的数据模拟一下就大概懂了

#include<algorithm>#include<cstdio>#include<iostream>using namespace std;#define maxn 100005struct point{    int left,right;    long long sum;//初始化的时候sum是当前这个区间的所有元素的和 其实sum究竟表示什么很难说清楚我感觉    //非要说的话他就是 原始的left right闭区间元素的和再加上后来在把某段区间的元素都增加一定值的时候在执行update时二分出的区间递归到能够小于或等于这个区间时的增加的和    //是不很拗口????反正我觉得是的,这个不用图很难表述清楚    long long jia;//对当前整个区间每个元素应该增加的值}node[4*maxn];int score[maxn];//原始的数据void buildtree(int left,int right,int u)//初始化的建树函数{    node[u].left=left;//设置区间的左端点    node[u].right=right;//设置区间的右端点    node[u].jia=0;//初始化整个区间每个元素都要增加的值为零    if(left==right) node[u].sum=score[left];//如果区间的长度为一则区间和就为它所存的元素    else//反之则二分递归下去    {        buildtree(left,(left+right)/2,2*u);        buildtree(((left+right)/2)+1,right,2*u+1);        node[u].sum=node[2*u].sum+node[2*u+1].sum;//当前区间的和为他左右的子区间的和    }};void updata(int l,int r,int val,int u)//更新区间,把区间l到r的元素都加上val{    node[u].sum+=(long long)(r-l+1)*(long long)val;//区间的和增加    int mid=(node[u].left+node[u].right)/2;//二分当前的区间    if(node[u].left==l&&node[u].right==r)//如果要跟新的区间与现在的区间是同一个区间就把每个元素要加的值加在jia上以便需要统计这段区间的和的时候用        node[u].jia+=(long long)val;    else if(r<=mid)//二分递归,        updata(l,r,val,2*u);    else if(l>mid)        updata(l,r,val,2*u+1);    else    {        updata(l,mid,val,2*u);        updata(mid+1,r,val,2*u+1);    }}int n,m;char temp;long long query(int left,int right,int u)//查询区间left到right区间的所有元素的和//left 和 right为要查找的区段和的区间{    int mid=(node[u].left+node[u].right)/2;//二分当前区间的中值    long long t=(long  long)(right-left+1)*(long long )node[u].jia;//t 也是一个不好描述的东西    //因为node[u].jia是 node[u].left 和node[u].right 内每个元素应该增加的值 所以要求 left到right这个包含在node[u].left 和node[u].right    //内的区间的元素的和当然要加上t了即(right-left+1)*node[u].jia 要注意可能会溢出    if(node[u].left==left&&node[u].right==right)//如果要求和的区间恰好的等于当前节点的区间就返回这个难懂的node[u].sum       return node[u].sum;    if(right<=mid)//在左区间就去左区间去找        return query(left,right,2*u)+t;    if(left>mid)//到右区间去找        return query(left,right,2*u+1)+t;    return  query(left,mid,2*u)+query(mid+1,right,2*u+1)+t;//否则就说明left到right区间横跨了左右2个子区间,就要把left到right的区间用mid分成2个部分}int main(){  //freopen("in.txt","r",stdin);    while(scanf("%d%c%d%c",&n,&temp,&m,&temp)!=EOF)    {        for(int i=1;i<=n;i++)            scanf("%d%c",&score[i],&temp);        char c;int s,e,h;        buildtree(1,n,1);        for(int i=0;i<m;i++)        {           scanf("%c%c",&c,&temp);            if(c=='C')            {                scanf("%d%c%d%c%d%c",&h,&temp,&s,&temp,&e,&temp);                updata(h,s,e,1);            }            if(c=='Q')            {                scanf("%d%c%d%c",&s,&temp,&e,&temp);                printf("%I64d\n",query(s,e,1));            }        }    }    return 0;}


原创粉丝点击