题目意思为:
给你n组数据,m次操作。(1~100000)
a1 ,a2,.....,an (-10^9<= a1 <=10^9).
Q X Y :输出X~Y数据之和。
C X Y Z:对X~Y组数据各加Z。
区间修改比点更新多了一个懒惰标记,保证算法的高效性。代码如下:
注意 32位不够用
#include <stdio.h>
#define MAX 100000
struct ac //线段树结构体
{
int l,r;
long long sign; //sign为懒惰标记
long long sum;
}t[4*MAX+5];
void build(int l,int r,int k) //建树
{
t[k].l=l;
t[k].r=r;
t[k].sign=0;
t[k].sum=0;
if(l==r)
return ;
int mid=(l+r)/2;
build(l,mid,2*k); //左边
build(mid+1,r,2*k+1); //右边
}
void tree_add(long long v,int d,int k) //输入叶子的值
{
if(t[k].l==t[k].r && t[k].l==d) //找到叶子,对其进行赋值
{
t[k].sum=v;
return ;
}
int mid=(t[k].l+t[k].r)/2;
if(d<=mid) //叶子在左边
tree_add(v,d,2*k);
else if(mid+1<=d) //叶子在右边
tree_add(v,d,2*k+1);
t[k].sum=t[2*k].sum+t[2*k+1].sum; //在添加叶子的同时,把结点的sum值更新
}
void tree_insert(int x,int y,long long c,int k) //区间修改,先更新懒惰标记再考虑sum
{
if(t[k].l==x && t[k].r==y) //若该区间为需要修改的区间
{
t[k].sign+=c; //注意,是懒惰标记加C
return ;
}
if(t[k].l<=x && y<=t[k].r) //若该区间不是所求区间,则更新sum值,继续往下递归
t[k].sum+=((y-x+1)*c);
int mid=(t[k].l+t[k].r)/2;
if(y<=mid) //若修改的区间全部在左边
tree_insert(x,y,c,2*k);
else if(mid+1<=x) //若修改的区间全部在右边
tree_insert(x,y,c,2*k+1);
else //修改的区间在两边
{
tree_insert(x,mid,c,2*k);
tree_insert(mid+1,y,c,2*k+1);
}
}
long long research(int x,int y,int k) //查找x~y的值之和
{
// printf("!!!!%lld \n",t[k].sum);
if(t[k].l==x && y==t[k].r) //查找区间在该节点区间内
return t[k].sum+(y-x+1)*t[k].sign; //注意,区间和由sum sign共同决定
if(t[k].sign) //若有懒惰标记
{
t[2*k].sign+=t[k].sign; //把懒惰赋值赋予下两个节点的懒惰标记
t[2*k+1].sign+=t[k].sign;
t[k].sum+=((t[k].r-t[k].l+1)*t[k].sign); //更新当前节点sum值
t[k].sign=0; //当前sum以为l~r区间之和,除去懒惰标记。
}
int mid=(t[k].l+t[k].r)/2;
if(y<=mid) //查找区间在左边
return research(x,y,2*k); //查找区间在右边
else if(mid+1<=x)
return research(x,y,2*k+1);
else //查找区间在两边
return research(x,mid,2*k)+research(mid+1,y,2*k+1);
}
void put(int k)
{
printf("k:%d sign:%lld sum:%lld\n",k,t[k].sign,t[k].sum);
if(t[k].l==t[k].r)
return ;
put(2*k);
put(2*k+1);
}
int main()
{
int n,q;
while(scanf("%d %d",&n,&q)!=EOF)
{
build(1,n,1);
int i;
long long v;
for(i=1;i<=n;i++)
{
scanf("%lld",&v);
tree_add(v,i,1);
}
// put(1);
char s[10],w;
int x,y;
long long c;
while(q--)
{
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%d %d",&x,&y);
printf("%lld\n",research(x,y,1));
}
else if(s[0]=='C')
{
scanf("%d %d %lld",&x,&y,&c);
tree_insert(x,y,c,1);
}
}
// put(1);
}
return 0;
}
线段树区间修改,最主要的代码是:
1.懒惰标记sign的加入,
2.sum,sign的更新,
3。通过sum,sign得出区间数值之和。