题目传送门:【模板】线段树 1 - 洛谷
上代码:
#include<bits/stdc++.h>
using namespace std;
long long n,shu_sum,q,h,m,a,l,r,a1;
struct hehe
{
long long l,r,f,w,zhi;
}tree[400005];//开大一些;
void build(long long int l,long long int r,long long int k)
{
tree[k].l=l;//tree是线段树数组l,r为left,right;
tree[k].r=r;
if(l==r)//表示已到叶子节点;可以直接输出;
{
scanf("%lld",&tree[k].zhi);
return ;
}
int mid=(l+r)/2;//二分
build(l,mid,k*2);//一个是k*2
build(mid+1,r,k*2+1);//一个位置是k*2+1//两个节点
tree[k].zhi=tree[k*2].zhi+tree[k*2+1].zhi;//节点的值是两个子节点之和;
}
void down(unsigned long long int k)
{
tree[k*2].zhi+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
tree[k*2].f+=tree[k].f;
tree[k*2+1].zhi+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
tree[k*2+1].f+=tree[k].f;
tree[k].f=0;
return ;
}
void xianzai(long long int k)//现在的位置
{
if(tree[k].l>=q&&tree[k].r<=h)//查找区间的开头和结尾
{
shu_sum+=tree[k].zhi;//shu_sum是加和。
return ;
}
if(tree[k].f!=0){//说说明已无符合要求的数;
down(k);
}
int mid=(tree[k].l+tree[k].r)/2;//获取子节点的结尾
if(q<=mid)//如果开头小于左子节点的结尾那么需要查看;
{
xianzai(k*2);
}
if(h>mid)//如果结尾大于右子节点的开头需要查看。
{
xianzai(k*2+1);
}
}
void xx(long long int k)
{
if(tree[k].l>=q&&tree[k].r<=h)
{
tree[k].zhi+=(tree[k].r-tree[k].l+1)*a;
tree[k].f+=a;
return;
}
if(tree[k].f!=0)
{
down(k);
}
int mid=(tree[k].l+tree[k].r)/2;
if(q<=mid)
{
xx(k*2);
}
if(h>mid)
{
xx(k*2+1);
}
tree[k].zhi=tree[k*2].zhi+tree[k*2+1].zhi;
return;
}
int main()
{
cin>>n>>m;
build(1,n,1);
for(int i=0;i<m;i++)
{
scanf("%lld",&a1);
if(a1==1)
{
scanf("%lld%lld%lld",&q,&h,&a);
xx(1);
}else if(a1==2)
{
scanf("%lld%lld",&q,&h);
shu_sum=0;//计数初始化为0;
xianzai(1);
cout<<shu_sum<<endl;
}
}
puts("\n");
system("pause");
return 0;
}