线段树 模版

来源:互联网 发布:centos共享文件夹在哪 编辑:程序博客网 时间:2024/05/01 04:19
  #include <iostream>#include<stdio.h>using namespace std;const int maxn=100002;int sum[maxn*4]={0};//这个要初始化为0int col[maxn*4]={0};//标记每个节点,初始化为0//将子节点的数据传到根节点void PushUp(int rt){//存放节点的总和    sum[rt]=sum[rt*2]+sum[rt*2+1];}//将m个值做标记void PushDownAdd(int rt,int m){    //如果该点做了标记    if(col[rt])    {        //那么为该点的孩子节点也做标记col[rt*2]+=col[rt];col[rt*2+1]+=col[rt];        //并修改该点孩子节点的值        sum[rt*2]+=(m-m/2)*col[rt];        sum[rt*2+1]+=(m/2)*col[rt];        col[rt]=0;//取消该点的标记    }}//将m个值做标记void PushDownValue(int rt,int m){    //如果该点做了标记    if(col[rt])    {        //那么为该点的孩子节点也做标记        col[rt*2]=col[rt*2+1]=col[rt];        //并修改该点孩子节点的值        sum[rt*2]=(m-m/2)*col[rt];        sum[rt*2+1]=(m/2)*col[rt];        col[rt]=0;//取消该点的标记    }}//递归创建树,并且更新到根节点,sum保存了这个线段的值void build(int l,int r,int rt){    if(l==r)    {cin>>sum[rt];        return;    }    int m=(l+r)/2;    build(l,m,rt*2);    build(m+1,r,rt*2+1);    PushUp(rt);}//在l到r区间中查找left到right区间的和int query(int left,int right,int l,int r,int rt){    if(l==left && r==right)    {        return sum[rt];    }PushDownAdd(rt,r-l+1);    int mid=(r+l)/2;    int ret=0;    if(right<=mid)//在左孩子{        ret+=query(left,right,l,mid,rt*2);}    else if(left>=mid+1)//在右孩子        ret+=query(left,right,mid+1,r,rt*2+1);    else//一半在左孩子一半在右孩子    {        //先查找left到mid区间的和,在计算mid+1到right区间的和        ret+=query(left,mid,l,mid,rt*2);        ret+=query(mid+1,right,mid+1,r,rt*2+1);    }    return ret;}//在l到r区间中更新left到right区间的值加上add,并且更新它父亲的值void updateAdd(int left,int right,int add,int l,int r,int rt){    //要更新的这个区间在l到r区间内    if(left<=l && r<=right)    {//只在该点做修改,其他点就不在修改,只是做标记        col[rt]+=add;//在该点做标记---标记累加        sum[rt]+=add*(r-l+1);//该点的值做修改        return;    }    //修改该点的孩子的值    PushDownAdd(rt,r-l+1);    int m=(l+r)/2;    if(left<=m)        updateAdd(left,right,add,l,m,rt*2);    if(right>m)        updateAdd(left,right,add,m+1,r,rt*2+1);    PushUp(rt);//更改rt节点的总和}//在l到r区间中更新left到right区间的值为add,并且更新它父亲的值void updateValue(int left,int right,int value,int l,int r,int rt){    //要更新的这个区间在l到r区间内    if(left<=l && r<=right)    {//只在该点做修改,其他点就不在修改,只是做标记        col[rt]=value;//在该点做标记        sum[rt]=value*(r-l+1);//该点的值做修改        return;    }    //修改该点的孩子的值    PushDownValue(rt,r-l+1);    int m=(l+r)/2;    if(left<=m)        updateValue(left,right,value,l,m,rt*2);    if(right>m)        updateValue(left,right,value,m+1,r,rt*2+1);    PushUp(rt);//更改rt节点的总和}int main(){int N,Q;    char ch;    int a,b;int c;    scanf("%d%d",&N,&Q);build(1,N,1);    while(Q--)    {cin>>ch;        if(ch=='Q')        {            scanf("%d%d",&a,&b);            printf("%d\n",query(a,b,1,N,1));        }        else if(ch=='C')        {            scanf("%d%d%d",&a,&b,&c);            updateAdd(a,b,c,1,N,1);        }    }    return 0;}

原创粉丝点击