pku3468(线段树)

基础的线段树区间修改和区间求和

贴代码吧

#include <stdio.h>
#define N 100010
struct Node
{
    int l,r;
    __int64 c,sum;//用c来存储在这个节点存储的增值,用sum来存储在该节点对应的区间上的和。 
}p[3*N];
int que[N];

void build(int k,int s,int t)
{
	int kl,kr,mid;
	p[k].l=s;p[k].r=t;p[k].c=0;
	p[k].sum=que[s];
	if(s==t) return ;
	mid=(s+t)>>1;kl=k<<1;kr=kl+1;
	build(kl,s,mid);
	build(kr,mid+1,t);
	p[k].sum=p[kl].sum+p[kr].sum;
}
//关键操作,传递时,把之前根节点更新的增值加到子节点,同时把子节点上的sum也更新了
//然后把根节点的值设置为0,以免重复加到子节点 
void trans(int k,int lk,int rk)
{
     p[lk].c+=p[k].c;
     p[rk].c+=p[k].c;
     p[lk].sum+=p[k].c*(p[lk].r-p[lk].l+1);
     p[rk].sum+=p[k].c*(p[rk].r-p[rk].l+1);
     p[k].c=0;
}

void insert(int k,int s,int t,int v)
{
	if(s<=p[k].l&&t>=p[k].r)
	{
		p[k].c+=v;
		p[k].sum+=v*(p[k].r-p[k].l+1);
	}
	else {
		int mid=(p[k].r+p[k].l)>>1,kl=k<<1,kr=kl+1;
		if(p[k].c!=0)
			trans(k,kl,kr);
		if(s<=mid) insert(kl,s,t,v);
		if(t>mid) insert(kr,s,t,v);
		p[k].sum=p[kr].sum+p[kl].sum;
	}
}

__int64 query(int k,int s,int t)
{
	if(s<=p[k].l&&t>=p[k].r)
		return p[k].sum;
	int mid=(p[k].r+p[k].l)>>1,kl=k<<1,kr=kl+1;
		if(p[k].c!=0)
			trans(k,kl,kr);
	__int64 a=0,b=0;
	if(s<=mid) a=query(kl,s,t);
	if(t>mid) b=query(kr,s,t);
	return a+b;
}

int main()
{
    char ch;
    int i,n,m,a,b,t;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;++i) scanf("%d",que+i);
        build(1,1,n);
        
        while(m--)
        {
            getchar();
            scanf("%c",&ch);
            if(ch=='Q')
            {
               scanf("%d %d",&a,&b);
               printf("%I64d\n",query(1,a,b));
            }
            else
            {
               scanf("%d %d %d",&a,&b,&t);
               insert(1,a,b,t);
            }
        }
    }
    return 0;
}




原文地址:https://www.cnblogs.com/nanke/p/2032216.html