题面
解法
文化课烂了之后回来写数据结构……
- 首先,我们明显可以将分子和分母分开来算。
- 对于分子,我们可以这样展开: ,然后我们可以发现,可以通过维护 , 和 来实现
- 对于分母,我们可以这样展开: ,然后可以发现,可以通过维护 和 来实现。
- 然后问题就是如果存在修改会出现什么情况。
- 先单独考虑操作 ,分子上的 会变成 ,影响并不是很大。分母上考虑如何修改 ,可以变成 来实现。
- 这样,我们就可以轻松自如地处理操作 。
- 然后考虑如何处理操作 。
- 分子上 会变成 ,维护起来也十分方便。分母上就比较简单了,就是连续一段的平方和或者是等差数列求和。
- 那么,我们不妨用一棵线段树来维护这个过程,中间需要打两个标记,一个为 表示操作 ,一个为 表示操作 。下传标记的时候注意一下标记的先后顺序问题就可以了。
- 时间复杂度: 。
代码
#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;
}