Description
你需要维护一个长度为 (n) 的实数对的序列,第 (i) 个元素为 ((x_i, y_i))。现有 (m) 次操作:
- ( exttt{1 L R}):设区间 ([L, R]) 的平均数 (ar x = frac{sum_{i=L}^R x_i}{R-L+1},ar y = frac{sum_{i=L}^R y_i}{R-L+1}),求
[a = dfrac{sum_{i=L}^R (x_i - ar x)(y_i - ar y)}{sum_{i=L}^R (x_i - ar x)^2}
]
的值。误差不超过 (10^{-5})。
-
( exttt{2 L R S T}):进行如下修改:
(forall iin[L, R],quad x_i leftarrow x_i + S)
(forall iin[L, R],quad y_i leftarrow y_i + T)
-
( exttt{3 L R S T}):进行如下修改:
(forall i in [L, R],quad x_i leftarrow i + S)
(forall i in [L, R],quad y_i leftarrow i + T)
Hint
(1le n, mle 10^5, 0le |S|, |T|le 10^5, 0le |x_i|, |y_i|le 10^5)
Solution
一道细节很多的线段树练手题。
在考虑怎么支持这些操作时不妨先看看我们需要维护些什么东西。拆开 (a) 这个柿子:
(下面用 (sum) 代替 (sum_{i=L}^R),用 (n) 代替 (R - L + 1))
[egin{aligned}
a = & dfrac{sum (x_i - ar x)(y_i - ar y)}{sum (x_i - ar x)^2} = dfrac A B \ \
A = & sum (x_i y_i - x_i ar y - y_i ar x_i + ar x ar y) \
= & sum x_i y_i - ar ysum x_i - ar xsum y_i + nar x ar y \
= & sum x_i y_i - frac{1}{n}sum x_i sum y_i \ \
B = & sum (x_i^2 + {ar x}^2 - 2x_iar x) \
= & sum x_i^2 +n{ar x}^2 - 2ar xsum x_i \
= & sum x_i^2 - frac{1}{n}left(sum x_i
ight)^2\
end{aligned}
]
将 (ar x, ar y) 展开的话,可以发现我们需要维护四个东西:
[egin{aligned}
A = & oxed{sum x_i y_i} - frac{1}{n}oxed{sum x_i} imes oxed{sum y_i} \
B = & oxed{sum x_i^2} - frac{1}{n}left(sum x_i
ight)^2\
end{aligned}
]
整坨柿子瞬间简洁可做了。
那么如何维护这四个信息呢?为了方便,我们用 (v_1, v_2, v_3, v_4) 分别代表 (sum x_i, sum y_i,sum x_i^2,sum x_i y_i)。
考虑修改操作之后这四个信息的变化:
- 操作 (2):
[egin{aligned}
&sum x_i osum(x_i+S)=sum x_i+nS & v_1 o v_1 + nS \
&sum y_i osum(y_i+T)=sum y_i+nT & v_2 o v_2 + nT \
&sum x_i^2 osum(x_i+S)^2=sum x_i^2+nS^2+2Ssum x_i& v_3 o v_3+nS^2+2Sv_1\
&sum x_i y_i osum(x_i+S)(y_i+T)=sum x_i y_i+Tsum x_i+Ssum y_i+nST & v_4 o v_4+Tv_1+Sv_2+nST\
end{aligned}
]
- 操作 (3):
- 记 (s_1 = sum_{i=L}^R i, s_2 = sum_{i=L}^R i^2)。
[egin{aligned}
&sum x_i osum(i+S)=s_1+nS & v_1 o s_1 + nS \
&sum y_i osum(i+T)=s_1+nT & v_2 o s_1 + nT \
&sum x_i^2 osum(i+S)^2=s_2+nS^2+2Ss_1& v_3 o s_2+nS^2+2Ss_1\
&sum x_i y_i osum(i+S)(i+T)=s_2+(T+S)s_1+nST & v_4 o s_2+(T+S)s_1+nST\
end{aligned}
]
于是就这样维护就行了,注意操作二的更新顺序。
其中 (s_1, s_2) 的计算可以预处理,也可以直接使用公式:
- (sum_{j=1}^i j = frac{i(i+1)}{2})
- (sum_{j=1}^i j^2 = frac{i(i+1)(2i+1)}{6})
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : SDOI2017 相关分析
*/
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int N = 1e5 + 5;
const int S = N << 2;
namespace calculator {
inline double sum(const double& l, const double& r) {
return (l + r) * (r - l + 1) / 2;
}
inline double sqrs(const double& p) {
return p * (p + 1) * (2 * p + 1) / 6;
}
}
struct dataType {
double sumx, sumy, sqrs, muls;
inline dataType()
: sumx(0.0), sumy(0.0), sqrs(0.0), muls(0.0) { }
inline dataType(const double& a, const double& b,
const double& c, const double& d)
: sumx(a), sumy(b), sqrs(c), muls(d) { }
inline dataType(const double& x, const double& y)
: sumx(x), sumy(y), sqrs(x * x), muls(x * y) { }
inline dataType operator + (const dataType& rhs) const {
return dataType(this->sumx + rhs.sumx, this->sumy + rhs.sumy,
this->sqrs + rhs.sqrs, this->muls + rhs.muls);
}
inline void update(const dataType& rhs) {
this->sumx += rhs.sumx, this->sumy += rhs.sumy;
this->sqrs += rhs.sqrs, this->muls += rhs.muls;
}
};
struct tagType {
double S, T;
inline tagType()
: S(0.0), T(0.0) { }
inline tagType(const double& s, const double& t)
: S(s), T(t) { }
inline bool operator == (const tagType& rhs) const {
return (fabs(this->S - rhs.S) <= 1e-8) && (fabs(this->T - rhs.T) <= 1e-8);
}
inline bool operator != (const tagType& rhs) const {
return !(*this == rhs);
}
};
const tagType std_cov(-1e18, -1e18);
const tagType std_add(0, 0);
int L[S], R[S];
dataType tr[S];
tagType cov[S];
tagType add[S];
#define mid ((L[x] + R[x]) / 2)
#define len double(R[x] - L[x] + 1)
inline void pushup(int x) {
tr[x] = tr[x << 1] + tr[x << 1 | 1];
}
inline void setCov(int x, const tagType& v) {
double s1 = calculator::sum(L[x], R[x]);
double s2 = calculator::sqrs(R[x]) - calculator::sqrs(L[x] - 1);
tr[x].sqrs = s2 + len * v.S * v.S + 2 * v.S * s1;
tr[x].muls = s2 + (v.S + v.T) * s1 + len * v.S * v.T;
tr[x].sumx = s1 + len * v.S;
tr[x].sumy = s1 + len * v.T;
cov[x] = v, add[x] = std_add;
}
inline void setAdd(int x, const tagType& v) {
tr[x].sqrs += v.S * v.S * len + 2 * v.S * tr[x].sumx;
tr[x].muls += v.S * tr[x].sumy + v.T * tr[x].sumx + len * v.S * v.T;
tr[x].sumx += v.S * len, tr[x].sumy += v.T * len;
add[x].S += v.S, add[x].T += v.T;
}
inline void pushdown(int x) {
if (cov[x] != std_cov) {
setCov(x << 1, cov[x]);
setCov(x << 1 | 1, cov[x]);
cov[x] = std_cov;
}
if (add[x] != std_add) {
setAdd(x << 1, add[x]);
setAdd(x << 1 | 1, add[x]);
add[x] = std_add;
}
}
void build(int x, int l, int r, double* datx, double* daty) {
L[x] = l, R[x] = r;
cov[x] = std_cov, add[x] = std_add;
if (l == r) {
tr[x] = dataType(datx[l], daty[l]);
return;
}
build(x << 1, l, mid, datx, daty);
build(x << 1 | 1, mid + 1, r, datx, daty);
pushup(x);
}
void modify(int x, int l, int r, void(*update)(int, const tagType&), const tagType& v) {
if (l <= L[x] && R[x] <= r) return update(x, v);
pushdown(x);
if (l <= mid) modify(x << 1, l, r, update, v);
if (r > mid) modify(x << 1 | 1, l, r, update, v);
pushup(x);
}
void query(int x, int l, int r, dataType& ret) {
if (l <= L[x] && R[x] <= r) return ret.update(tr[x]);
if (l > R[x] || L[x] > r) return;
pushdown(x), query(x << 1, l, r, ret), query(x << 1 | 1, l, r, ret);
}
#undef mid
#undef len
int n, Q;
double x[N], y[N];
signed main() {
scanf("%d%d", &n, &Q);
for (int i = 1; i <= n; i++) scanf("%lf", x + i);
for (int i = 1; i <= n; i++) scanf("%lf", y + i);
build(1, 1, n, x, y);
while (Q--) {
int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if (opt == 1) {
dataType res; query(1, l, r, res);
double len = r - l + 1;
double avex = res.sumx / len;
double avey = res.sumy / len;
double A = res.muls - res.sumx * res.sumy / len;
double B = res.sqrs - res.sumx * res.sumx / len;
printf("%lf
", A / B);
} else {
tagType val; scanf("%lf%lf", &val.S, &val.T);
modify(1, l, r, (opt == 2 ? setAdd : setCov), val);
}
}
}