CSUSTOJ 1127-区间方差(线段树)
题目链接:http://acm.csust.edu.cn/problem/1127
CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/108026329
Description
线段树进阶题
n个数m次操作1 pos x 将位置为pos的值修改为x
2 l r 查询区间l,r的方差乘以区间长度的平方
Input
输入:第一行,n,m
接下来一行n个数接下来m行操作
\(1\ pos\ x\ 2\ l\ r(1 \leq n, m \leq 2^{16})(0\leq ai\leq 10^4)\)
Output
输出每次询问的值
Sample Input 1
4 4
1 2 3 4
2 1 4
1 2 4
2 1 4
2 2 4
Sample Output 1
20
24
2
emmm,题面有点难看。。。可能是当时出题人还不太会Markdown吧。
我们可以先写出它要用的公式:\(S^2=\frac{\sum_{i=l}^r(a_i-\bar{a})^2}{r-l+1}\times (r-l+1)^2\)
接下来我们就是将其化简一波:
\(S^2=\sum_{i=l}^r(a_i-\bar a)^2\times L\)
\(\ \ \ \ \ =L\sum_{i=l}^ra_i^2+(\frac{sum}{L})^2-2a_i\frac{sum}{L}\)
\(\ \ \ \ \ =\sum a_i^2L+\sum \frac{sum^2}{L}-\sum 2a_isum\)
\(\ \ \ \ \ =L\sum a_i^2+L\frac{sum^2}{L}-2sum\sum a_i\)
\(\ \ \ \ \ =L\sum a_i^2+sum^2-2sum^2\)
\(\ \ \ \ \ =L\sum a_i^2-sum^2\)
于是就会发现。。。。这不就是个sb线段树嘛。。。。维护一下区间和,维护一下区间平方和就完事了。
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lc rt<<1
#define rc rt<<1|1
typedef long long ll;
const int mac=1e5+10;
int a[mac];
ll sum[mac<<2],suma2[mac<<2];
ll ans1=0,ans2=0;
ll pw2(ll x) {return x*x;}
void push_up(int rt)
{
sum[rt]=sum[lc]+sum[rc];
suma2[rt]=suma2[lc]+suma2[rc];
}
void build(int l,int r,int rt)
{
if (l==r){
sum[rt]=a[l];
suma2[rt]=pw2(a[l]);
return;
}
int mid=(l+r)>>1;
build(lson); build(rson);
push_up(rt);
}
void update(int l,int r,int rt,int pos,int val)
{
if (l==r){
sum[rt]=val;
suma2[rt]=pw2(val);
return;
}
int mid=(l+r)>>1;
if (mid>=pos) update(lson,pos,val);
else update(rson,pos,val);
push_up(rt);
}
void query(int l,int r,int rt,int L,int R)
{
if (l>=L && r<=R){
ans1+=suma2[rt];
ans2+=sum[rt];
return;
}
int mid=(l+r)>>1;
if (mid>=L) query(lson,L,R);
if (mid<R) query(rson,L,R);
}
int main(int argc, char const *argv[])
{
int n,m;
scanf ("%d%d",&n,&m);
for (int i=1; i<=n; i++) scanf ("%d",&a[i]);
build(1,n,1);
for (int i=1; i<=m; i++){
int opt,l,r,pos,x;
scanf ("%d",&opt);
if (opt==1){
scanf ("%d%d",&pos,&x);
update(1,n,1,pos,x);
}
else {
scanf ("%d%d",&l,&r);
if (l==r) {printf("0\n"); continue;}
ans1=0; ans2=0;
query(1,n,1,l,r);
printf("%lld\n",(r-l+1)*ans1-pw2(ans2));
}
}
return 0;
}