[SDOI2017]相關分析 題解
題意
給定兩個陣列$x, y$,有三種操作
- 給定$l, r$,令$\overline x = \frac{1}{r - l + 1}\sum_{i = l}^r x_i,\overline y= \frac{1}{r - l + 1}\sum_{i = l}^r y_i$,即該陣列$[l,r]$間數的平均數,求$$\frac{\sum_{i=l}^r(x_i-\overline x)(y_i-\overline y)}{\sum_{i=l}^r (x_i-\overline x) ^2}$$
- 給定$l,r,s,t$,對任意$i\in[l,r],x_i = x_i + s, y_i = y_i + t$
- 給定$l,r,s,t$,對任意$i\in[l,r],x_i = i + s, y_i = i+t$
Sol
化簡一波式子
$$\frac{\sum_{i=l}^r(x_i-\overline x)(y_i-\overline y)}{\sum_{i=l}^r (x_i-\overline x) ^2}$$
拆開乘積與平方,此處記$\sum_{i=l}^r$為$\sum$
$$=\frac{\sum x_iy_i - \sum \overline x y_i - \sum\overline y x_i + (r-l+1)\overline x\overline y}{\sum x_i^2 - 2\sum\overline x x_i+(r-l+1)\overline x_i^2}$$
將$\overline x,\overline y$代入
$$=\frac{\sum x_i y_i - \frac{\sum x_i \sum y_i}{r-l+1} - \frac{\sum x_i \sum y_i}{r-l+1}+(r-l+1)\frac{\sum x_i}{r-l+1}\frac{\sum y_i}{r-l+1}}{\sum x_i^2 - \frac{\sum x_i}{r-l+1}-(r-l+1)\frac{\sum x_i}{r-l+1}\frac{\sum x_i}{r-l+1}}$$
化簡一波
$$=\frac{\sum x_iy_i - \frac{\sum x_i\sum y_i}{r-l+1}}{\sum x_i^2 + \frac{(\sum x_i)^2}{r-l+1}}$$
所以我們要維護$4$個東西:$\sum x_i, \sum y_i,\sum x_i^2, \sum x_iy_i$
$1$操作
直接按照推出來的式子進行作答即可
$2$操作
$\sum (x_i + s) ^2 = \sum x_i^2 + 2s\sum x_i+s^2 (r-l+1)$
$\sum(x_i+s)(y_i+t)=\sum x_iy_i+s\sum y_i+t\sum x_i+st(r-l+1)$
$\sum (x_i+s)=\sum x_i+s(r-l+1)$
$\sum(y_i+t)=\sum y_i+t(r-l+1)$
下面兩項的值會被上面兩項在修改時引用,所以先修改上面兩項。
$3$操作
前置公式:$1^2+2^2+...+n^2=\frac{n(n+1)(2n+1)}{6}$
我們把操作拆分成兩步
- 對於任意$i\in[l,r],x_i = y_i = i$
- 對於任意$i\in[l,r],x_i=x_i+s,y_i=y_i+t$
對於第二步,用上面的方法即可
對於第一步,我們看每一個要維護的值是多少
$\sum i^2 = \frac{r(r+1)(2r+1)-l(l-1)(2l-1)}{6}$
$\sum i=\frac{(r-l+1)(r+l)}{2}$
$O(1)$求出即可。
#include<bits/stdc++.h> #define int long long using namespace std; double x[100005], y[100005]; double A[400005], B[400005], C[400005], D[400005], addS[400005], addT[400005], covS[400005], covT[400005]; void pushup(int o) { A[o] = A[o << 1] + A[o << 1 | 1]; B[o] = B[o << 1] + B[o << 1 | 1]; C[o] = C[o << 1] + C[o << 1 | 1]; D[o] = D[o << 1] + D[o << 1 | 1]; } void build(int o, int l, int r) { covS[o] = covT[o] = 1E9; if(l == r) { A[o] = x[l] * x[l]; B[o] = x[l] * y[l]; C[o] = x[l], D[o] = y[l]; return ; } int mid = (l + r) >> 1; build(o << 1, l, mid); build(o << 1 | 1, mid + 1, r); pushup(o); } void pusha(int o, double aS, double aT, int l, int r) { addS[o] += aS, addT[o] += aT; A[o] = A[o] + 2 * aS * C[o] + aS * aS * (r - l + 1); B[o] = B[o] + aS * D[o] + aT * C[o] + aS * aT * (r - l + 1); C[o] = C[o] + aS * (r - l + 1); D[o] = D[o] + aT * (r - l + 1); } void pushc(int o, double cS, double cT, int l, int r) { addS[o] = 0, addT[o] = 0; covS[o] = cS, covT[o] = cT; A[o] = B[o] = r * (r + 1) * (2 * r + 1) / 6 - l * (l - 1) * (2 * l - 1) / 6; C[o] = D[o] = (r - l + 1) * (r + l) / 2; pusha(o, cS, cT, l, r); } void pushdown(int o, int l, int r) { if(covS[o] != 1E9 || covT[o] != 1E9) { int mid = (l + r) >> 1; pushc(o << 1, covS[o], covT[o], l, mid); pushc(o << 1 | 1, covS[o], covT[o], mid + 1, r); addS[o] -= covS[o], addT[o] -= covT[o]; covS[o] = covT[o] = 1E9; } if(addS[o] || addT[o]) { int mid = (l + r) >> 1; pusha(o << 1, addS[o], addT[o], l, mid); pusha(o << 1 | 1, addS[o], addT[o], mid + 1, r); addS[o] = addT[o] = 0; } } void modify_add(int o, int l, int r, int nl, int nr, double S, double T) { if(nl <= l && r <= nr) { pusha(o, S, T, l, r); return ; } pushdown(o, l, r); int mid = (l + r) >> 1; if(nl <= mid) modify_add(o << 1, l, mid, nl, nr, S, T); if(mid < nr) modify_add(o << 1 | 1, mid + 1, r, nl, nr, S, T); pushup(o); } void modify_cov(int o, int l, int r, int nl, int nr, double S, double T) { if(nl <= l && r <= nr) { pushc(o, S, T, l, r); return ; } pushdown(o, l, r); int mid = (l + r) >> 1; if(nl <= mid) modify_cov(o << 1, l, mid, nl, nr, S, T); if(mid < nr) modify_cov(o << 1 | 1, mid + 1, r, nl, nr, S, T); pushup(o); } struct node { double A, B, C, D; node(double a = 0, double b = 0, double c = 0, double d = 0) {A = a, B = b, C = c, D = d;} }; node operator + (node X, node Y) { node Z; Z.A = X.A + Y.A; Z.B = X.B + Y.B; Z.C = X.C + Y.C; Z.D = X.D + Y.D; return Z; } node query(int o, int l, int r, int nl, int nr) { if(nl <= l && r <= nr) return node(A[o], B[o], C[o], D[o]); pushdown(o, l, r); int mid = (l + r) >> 1; node ans; if(nl <= mid) ans = ans + query(o << 1, l, mid, nl, nr); if(mid < nr) ans = ans + query(o << 1 | 1, mid + 1, r, nl, nr); return ans; } signed main() { int n, m; scanf("%lld%lld", &n, &m); 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); for(int i = 1; i <= m; i++) { int opt, l, r; double s, t; scanf("%lld%lld%lld", &opt, &l, &r); if(opt == 1) { node S = query(1, 1, n, l, r); printf("%.10lf\n", (S.B - S.C * S.D / (r - l + 1)) / (S.A - S.C * S.C / (r - l + 1))); } if(opt == 2) { scanf("%lf%lf", &s, &t); modify_add(1, 1, n, l, r, s, t); } if(opt == 3) { scanf("%lf%lf", &s, &t); modify_cov(1, 1, n, l, r, s, t); } } }View Code