题目
满足区间查找和区间维护方差
分析
看到这两个操作,我第一时间想到了线段树,但是貌似常数有点大,于是我又尝(zuo)试(si)打zkw线段树,改了一天也没改出来,第二天又改回线段树,结果WA50分,晚上又尝(zuo)试(si)用树状数组,然后就一脸懵逼,最后只好找回老本,线段树,发现没开long long,然后就在今晚9点多改A了,讲一下主要的思路
首先方差公式
1
r
−
l
+
1
∑
i
=
l
r
(
a
[
i
]
−
a
.
a
v
e
)
2
\frac{1}{r-l+1}\sum_{i=l}^r(a[i]-a.ave)^2
r−l+11i=l∑r(a[i]−a.ave)2
化简得到
1
r
−
l
+
1
∑
i
=
l
r
(
a
[
i
]
2
−
2
a
[
i
]
a
.
a
v
e
+
a
.
a
v
e
2
)
\frac{1}{r-l+1}\sum_{i=l}^r(a[i]^2-2a[i]a.ave+a.ave^2)
r−l+11i=l∑r(a[i]2−2a[i]a.ave+a.ave2)
也就是
1
r
−
l
+
1
∑
i
=
l
r
a
[
i
]
2
−
∑
i
=
l
r
2
a
[
i
]
a
.
a
v
e
+
∑
i
=
l
r
a
.
a
v
e
2
\frac{1}{r-l+1}\sum_{i=l}^ra[i]^2-\sum_{i=l}^r2a[i]a.ave+\sum_{i=l}^ra.ave^2
r−l+11i=l∑ra[i]2−i=l∑r2a[i]a.ave+i=l∑ra.ave2
=
1
r
−
l
+
1
∑
i
=
l
r
a
[
i
]
2
−
a
.
a
v
e
(
∑
i
=
l
r
2
a
[
i
]
+
∑
i
=
l
r
a
.
a
v
e
)
=\frac{1}{r-l+1}\sum_{i=l}^ra[i]^2-a.ave(\sum_{i=l}^r2a[i]+\sum_{i=l}^ra.ave)
=r−l+11i=l∑ra[i]2−a.ave(i=l∑r2a[i]+i=l∑ra.ave)
=
1
r
−
l
+
1
∑
i
=
l
r
a
[
i
]
2
−
a
.
a
v
e
(
∑
i
=
l
r
2
a
[
i
]
+
∑
i
=
l
r
a
[
i
]
)
=\frac{1}{r-l+1}\sum_{i=l}^ra[i]^2-a.ave(\sum_{i=l}^r2a[i]+\sum_{i=l}^ra[i])
=r−l+11i=l∑ra[i]2−a.ave(i=l∑r2a[i]+i=l∑ra[i])
为了精度问题,分子分母同乘
(
r
−
l
+
1
)
(r-l+1)
(r−l+1)可以得到
=
1
(
r
−
l
+
1
)
2
(
r
−
l
+
1
)
∑
i
=
l
r
a
[
i
]
2
−
(
∑
i
=
l
r
a
[
i
]
)
2
=\frac{1}{(r-l+1)^2}(r-l+1)\sum_{i=l}^ra[i]^2-(\sum_{i=l}^ra[i])^2
=(r−l+1)21(r−l+1)i=l∑ra[i]2−(i=l∑ra[i])2
那么可以发现只需要维护区间和以及区间平方和即可,那如何修改平方和?
∑
i
=
l
r
(
a
[
i
]
+
t
)
2
=
∑
i
=
l
r
a
[
i
]
2
+
∑
i
=
l
r
2
a
[
i
]
t
+
(
r
−
l
+
1
)
t
2
\sum_{i=l}^r(a[i]+t)^2=\sum_{i=l}^ra[i]^2+\sum_{i=l}^r2a[i]t+(r-l+1)t^2
i=l∑r(a[i]+t)2=i=l∑ra[i]2+i=l∑r2a[i]t+(r−l+1)t2
只需要维护
∑
i
=
l
r
2
a
[
i
]
t
+
(
r
−
l
+
1
)
t
2
\sum_{i=l}^r2a[i]t+(r-l+1)t^2
∑i=lr2a[i]t+(r−l+1)t2即可
代码(还教室)
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100010; int n,m;
typedef long long ll;
ll w1[N<<2],w2[N<<2],laz[N<<2],a[N];
inline ll iut(){
rr ll ans=0,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans*f;
}
inline void print(ll ans){
if (ans<0) ans=-ans,putchar('-');
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void pup(int k){w1[k]=w1[k<<1]+w1[k<<1|1],w2[k]=w2[k<<1]+w2[k<<1|1];}
inline void pdown(int k,int l,int r,ll t){
laz[k]+=t;
w2[k]+=2*t*w1[k]+t*t*(r-l+1);
w1[k]+=t*(r-l+1);
}
inline void build(int k,int l,int r){
if (l==r) {w1[k]=a[l],w2[k]=a[l]*a[l]; return;}
rr int mid=(l+r)>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
pup(k);
}
inline void pr(int k,int l,int r){
rr int mid=(l+r)>>1;
pdown(k<<1,l,mid,laz[k]);
pdown(k<<1|1,mid+1,r,laz[k]);
laz[k]=0;
}
inline void update(int k,int l,int r,int x,int y,ll t){
if (x<=l&&r<=y) {pdown(k,l,r,t); return;}
pr(k,l,r); rr int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x,y,t);
if (y>mid) update(k<<1|1,mid+1,r,x,y,t);
pup(k);
}
inline ll query1(int k,int l,int r,int x,int y){
if (x<=l&&r<=y) return w1[k]; rr ll ans=0;
pr(k,l,r); rr int mid=(l+r)>>1;
if (x<=mid) ans+=query1(k<<1,l,mid,x,y);
if (y>mid) ans+=query1(k<<1|1,mid+1,r,x,y);
return ans;
}
inline ll query2(int k,int l,int r,int x,int y){
if (x<=l&&r<=y) return w2[k]; rr ll ans=0;
pr(k,l,r); rr int mid=(l+r)>>1;
if (x<=mid) ans+=query2(k<<1,l,mid,x,y);
if (y>mid) ans+=query2(k<<1|1,mid+1,r,x,y);
return ans;
}
signed main(){
n=iut(); m=iut();
for (rr int i=1;i<=n;++i) a[i]=iut();
build(1,1,n);
while (m--){
rr int q=iut(),x=iut(),y=iut();
if (q==1) update(1,1,n,x,y,iut());
else if (q==2){
rr ll t=query1(1,1,n,x,y);
rr ll g=y-x+1,h=__gcd(t,g);
print(t/h); putchar('/');
print(g/h); putchar(10);
}
else{
rr ll t1=query1(1,1,n,x,y),t2=query2(1,1,n,x,y);
rr ll t=t2*(y-x+1)-t1*t1;
rr ll g=(long long)(y-x+1)*(y-x+1),h=__gcd(t,g);
print(t/h); putchar('/');
print(g/h); putchar(10);
}
}
return 0;
}