题面
解法
文化课烂了之后回来写数据结构……
- 首先,我们明显可以将分子和分母分开来算。
- 对于分子,我们可以这样展开: ∑ ( x i y i − x ˉ y i − y ˉ x i + x ˉ y ˉ ) = ∑ x i y i − x ˉ ∑ y i \sum(x_iy_i-\bar xy_i-\bar yx_i+\bar x\bar y)=\sum x_iy_i-\bar x\sum y_i ∑(xiyi−xˉyi−yˉxi+xˉyˉ)=∑xiyi−xˉ∑yi,然后我们可以发现,可以通过维护 ∑ x i y i \sum x_iy_i ∑xiyi, ∑ x i \sum x_i ∑xi和 ∑ y i \sum y_i ∑yi来实现
- 对于分母,我们可以这样展开: ∑ ( x i 2 + x ˉ 2 − 2 x ˉ x i ) = ∑ ( x i 2 + x ˉ 2 ) − 2 x ˉ ∑ x i \sum (x_i^2+\bar x^2-2\bar xx_i)=\sum(x_i^2+\bar x^2)-2\bar x\sum x_i ∑(xi2+xˉ2−2xˉxi)=∑(xi2+xˉ2)−2xˉ∑xi,然后可以发现,可以通过维护 ∑ x i 2 \sum x_i^2 ∑xi2和 ∑ x i \sum x_i ∑xi来实现。
- 然后问题就是如果存在修改会出现什么情况。
- 先单独考虑操作 2 2 2,分子上的 ∑ x i y i \sum x_iy_i ∑xiyi会变成 ∑ ( x i + s ) ( y i + t ) = ∑ x i y i + t ∑ x i + s ∑ y i + ∑ s t \sum (x_i+s)(y_i+t)=\sum x_iy_i+t\sum x_i+s\sum y_i+\sum st ∑(xi+s)(yi+t)=∑xiyi+t∑xi+s∑yi+∑st,影响并不是很大。分母上考虑如何修改 ∑ x i 2 \sum x_i^2 ∑xi2,可以变成 ∑ ( x i + s ) 2 = ∑ x i 2 + ∑ s 2 + 2 s ∑ x i \sum (x_i+s)^2=\sum x_i^2+\sum s^2+2s\sum x_i ∑(xi+s)2=∑xi2+∑s2+2s∑xi来实现。
- 这样,我们就可以轻松自如地处理操作 2 2 2。
- 然后考虑如何处理操作 3 3 3。
- 分子上 ∑ x i y i \sum x_iy_i ∑xiyi会变成 ∑ s t + ( s + t ) ∑ i + ∑ i 2 \sum st+(s+t)\sum i+\sum i^2 ∑st+(s+t)∑i+∑i2,维护起来也十分方便。分母上就比较简单了,就是连续一段的平方和或者是等差数列求和。
- 那么,我们不妨用一棵线段树来维护这个过程,中间需要打两个标记,一个为 ( a d d s , a d d t ) (add_s,add_t) (adds,addt)表示操作 2 2 2,一个为 ( s e t s , s e t t ) (set_s,set_t) (sets,sett)表示操作 3 3 3。下传标记的时候注意一下标记的先后顺序问题就可以了。
- 时间复杂度: O ( m log n ) O(m\log n) O(mlogn)。
代码
#include <bits/stdc++.h>
#define mp make_pair
#define N 100010
using namespace std;
template <typename T> void chkmax(T &x, T y) {x = x > y ? x : y;}
template <typename T> void chkmin(T &x, T y) {x = x < y ? x : y;}
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
double x[N], y[N], s1[N], s2[N]; int n, m;
struct SegmentTree {
#define lc k << 1
#define rc k << 1 | 1
struct Node {double s, t, fs, ft, sx, sy, sxy, sx2;} t[N * 4];
void update(int k) {
t[k].sx = t[lc].sx + t[rc].sx, t[k].sy = t[lc].sy + t[rc].sy;
t[k].sxy = t[lc].sxy + t[rc].sxy, t[k].sx2 = t[lc].sx2 + t[rc].sx2;
}
void calc1(int k, double x, double y, int l, int r) {
t[k].s += x, t[k].t += y;
t[k].sxy += t[k].sx * y + t[k].sy * x + (r - l + 1) * x * y;
t[k].sx2 += 2 * x * t[k].sx + (r - l + 1) * x * x;
t[k].sx += (r - l + 1) * x, t[k].sy += (r - l + 1) * y;
}
void calc2(int k, double x, double y, int l, int r) {
t[k].s = t[k].t = 0, t[k].fs = x, t[k].ft = y;
t[k].sxy = x * y * (r - l + 1) + (s1[r] - s1[l - 1]) * (x + y) + s2[r] - s2[l - 1];
t[k].sx = x * (r - l + 1) + s1[r] - s1[l - 1];
t[k].sy = y * (r - l + 1) + s1[r] - s1[l - 1];
t[k].sx2 = x * x * (r - l + 1) + 2 * x * (s1[r] - s1[l - 1]) + s2[r] - s2[l - 1];
}
void pushdown(int k, int l, int r) {
double fx = t[k].fs, fy = t[k].ft, x = t[k].s, y = t[k].t;
int mid = (l + r) >> 1;
if (fabs(fx) < 1e9) calc2(lc, fx, fy, l, mid), calc2(rc, fx, fy, mid + 1, r);
calc1(lc, x, y, l, mid), calc1(rc, x, y, mid + 1, r);
t[k].fs = t[k].ft = 1e9, t[k].s = t[k].t = 0;
}
void build(int k, int l, int r) {
t[k] = (Node) {0, 0, 1e9, 1e9, 0, 0, 0, 0};
if (l == r) {
t[k].sx = x[l], t[k].sy = y[l];
t[k].sxy = x[l] * y[l], t[k].sx2 = x[l] * x[l];
return;
}
int mid = (l + r) >> 1;
build(lc, l, mid), build(rc, mid + 1, r);
update(k);
}
void modify(int k, int l, int r, int L, int R, double x, double y) {
if (L <= l && r <= R) return calc1(k, x, y, l, r), void();
pushdown(k, l, r);
int mid = (l + r) >> 1;
if (L <= mid) modify(lc, l, mid, L, R, x, y);
if (R > mid) modify(rc, mid + 1, r, L, R, x, y);
update(k);
}
void Modify(int k, int l, int r, int L, int R, double x, double y) {
if (L <= l && r <= R) return calc2(k, x, y, l, r), void();
pushdown(k, l, r); int mid = (l + r) >> 1;
if (L <= mid) Modify(lc, l, mid, L, R, x, y);
if (R > mid) Modify(rc, mid + 1, r, L, R, x, y);
update(k);
}
Node query(int k, int l, int r, int L, int R) {
if (L <= l && r <= R) return t[k];
pushdown(k, l, r);
int mid = (l + r) >> 1;
Node tx = (Node) {0, 0, 1e9, 1e9, 0, 0, 0, 0}, ty = (Node) {0, 0, 1e9, 1e9, 0, 0, 0, 0};
if (L <= mid) tx = query(lc, l, mid, L, R);
if (R > mid) ty = query(rc, mid + 1, r, L, R);
Node ret = (Node) {0, 0, 1e9, 1e9, 0, 0, 0, 0};
ret.sx = tx.sx + ty.sx, ret.sy = tx.sy + ty.sy;
ret.sxy = tx.sxy + ty.sxy, ret.sx2 = tx.sx2 + ty.sx2;
return ret;
}
double ask(int l, int r) {
Node tmp = query(1, 1, n, l, r);
double ave = tmp.sx / (r - l + 1);
double tx = tmp.sxy - ave * tmp.sy, ty = tmp.sx2 + (r - l + 1) * ave * ave - 2 * ave * tmp.sx;
return tx / ty;
}
} T;
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++) s1[i] = s1[i - 1] + i, s2[i] = s2[i - 1] + 1ll * i * i;
for (int i = 1; i <= n; i++) read(x[i]);
for (int i = 1; i <= n; i++) read(y[i]);
T.build(1, 1, n);
while (m--) {
int op, l, r; read(op), read(l), read(r);
if (op == 1) {cout << fixed << setprecision(8) << T.ask(l, r) << "\n"; continue;}
int s, t; read(s), read(t);
if (op == 2) T.modify(1, 1, n, l, r, s, t); else T.Modify(1, 1, n, l, r, s, t);
}
return 0;
}