目录:
题目:
分析:
树状数组:
设
tree[i]=a[i]−a[i−1]
t
r
e
e
[
i
]
=
a
[
i
]
−
a
[
i
−
1
]
(差分),那么容易得到:
tree[1]+tree[2]+…+tree[i]=a[i]
t
r
e
e
[
1
]
+
t
r
e
e
[
2
]
+
…
+
t
r
e
e
[
i
]
=
a
[
i
]
这个公式
所以,只需要维护
tree
t
r
e
e
数组就可以实现区间修改了。
如何实现区间查询呢?
我们已经推出了一个公式:
tree[1]+tree[2]+…tree[i]=a[i]
t
r
e
e
[
1
]
+
t
r
e
e
[
2
]
+
…
t
r
e
e
[
i
]
=
a
[
i
]
那么,对于1到r的区间和,即为:
a[1]+a[2]+……+a[r−1]+a[r]
a
[
1
]
+
a
[
2
]
+
…
…
+
a
[
r
−
1
]
+
a
[
r
]
=tree[1]+(tree[1]+tree[2])+…+(tree[1]+…+tree[r])
=
t
r
e
e
[
1
]
+
(
t
r
e
e
[
1
]
+
t
r
e
e
[
2
]
)
+
…
+
(
t
r
e
e
[
1
]
+
…
+
t
r
e
e
[
r
]
)
=(tree[1]∗r)+(tree[2]∗r−1)+…(tree[r]∗1)
=
(
t
r
e
e
[
1
]
∗
r
)
+
(
t
r
e
e
[
2
]
∗
r
−
1
)
+
…
(
t
r
e
e
[
r
]
∗
1
)
=r∗(tree[1]+tree[2]+…+tree[r])−(tree[1]∗0+tree[2]∗1+…+tree[r]∗(r−1))
=
r
∗
(
t
r
e
e
[
1
]
+
t
r
e
e
[
2
]
+
…
+
t
r
e
e
[
r
]
)
−
(
t
r
e
e
[
1
]
∗
0
+
t
r
e
e
[
2
]
∗
1
+
…
+
t
r
e
e
[
r
]
∗
(
r
−
1
)
)
对于
a
a
的树状数组(差分),建立一个新的树状数组
tree1
t
r
e
e
1
使得:
tree1[i]=tree[i]∗(i−1)
t
r
e
e
1
[
i
]
=
t
r
e
e
[
i
]
∗
(
i
−
1
)
之后,x到y的区间和即为:
(y∗sum(tree,y)−(x−1)∗sum(tree,x−1))−(sum(tree1,y)−sum(tree1,x−1))
(
y
∗
s
u
m
(
t
r
e
e
,
y
)
−
(
x
−
1
)
∗
s
u
m
(
t
r
e
e
,
x
−
1
)
)
−
(
s
u
m
(
t
r
e
e
1
,
y
)
−
s
u
m
(
t
r
e
e
1
,
x
−
1
)
)
线段树:
对于线段树的做法还是很简单的,只需要注意用 long l o n g long l o n g 就好了
代码:
树状数组:
//2641MS
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int min(int x,int y)
{ return x<y? x:y; }
int max(int x,int y)
{ return x>y? x:y; }
LL c[2][100001];
int n=read(),q=read();
void add(int w,int x,int y)
{
for(;x<=n;x+=x&-x) c[w][x]+=y;
return;
}
LL ask(int w,int x)
{
LL ans=0;
for(;x;x-=x&-x) ans+=c[w][x];
return ans;
}
LL sum[100001];
int main()
{
int x[100001];
for(int i=1;i<=n;i++) x[i]=read(),sum[i]=sum[i-1]+x[i];
char c;
while(q--)
{
cin>>c;
int l=read(),r=read();
if(c=='C')
{
int d=read();
add(0,l,d);
add(0,r+1,-d);
add(1,l,d*l);
add(1,r+1,-(r+1)*d);
}
else
{
LL ans=sum[r]+(r+1)*ask(0,r)-ask(1,r);
ans-=sum[l-1]+l*ask(0,l-1)-ask(1,l-1);
printf("%lld\n",ans);
}
}
return 0;
}
线段树:
//3297MS
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
struct segmentree{
int l,r;
LL sum,add;
}t[400040];
int x[100001];
void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;
if(l==r) {t[p].sum=x[l];return;}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
return;
}
void spread(int p)
{
if(t[p].add)
{
t[p*2].sum+=t[p].add*(t[p*2].r-t[p*2].l+1);
t[p*2+1].sum+=t[p].add*(t[p*2+1].r-t[p*2+1].l+1);
t[p*2].add+=t[p].add;t[p*2+1].add+=t[p].add;
t[p].add=0;
}
return;
}
void change(int p,int l,int r,int w)
{
if(l<=t[p].l&&r>=t[p].r)
{
t[p].sum+=(long long)w*(t[p].r-t[p].l+1);
t[p].add+=w;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change(p*2,l,r,w);
if(r>mid) change(p*2+1,l,r,w);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
return;
}
LL ask(int p,int l,int r)
{
if(l<=t[p].l&&r>=t[p].r) return t[p].sum;
spread(p);
int mid=(t[p].l+t[p].r)>>1;
LL val=0;
if(l<=mid) val+=ask(p*2,l,r);
if(r>mid) val+=ask(p*2+1,l,r);
return val;
}
int main()
{
int n=read(),q=read();
for(int i=1;i<=n;i++) x[i]=read();
build(1,1,n);
char c;
int l,r;
while(q--)
{
cin>>c;l=read();r=read();
if(c=='C')
{
int w=read();
change(1,l,r,w);
}
else
printf("%lld\n",ask(1,l,r));
}
return 0;
}