Description
给定序列 x = ( x 1 , x 2 , ⋯ , x n ) , y = ( y 1 , y 2 , ⋯ , y n ) x=(x_1,x_2,\cdots,x_n),y=(y_1,y_2,\cdots,y_n) x=(x1,x2,⋯,xn),y=(y1,y2,⋯,yn),有 m m m 个操作分三种:
- query ( l , r ) \operatorname{query}(l,r) query(l,r):求 ∑ i = l r ( x i − x l ⋯ r ‾ ) ( y i − y l ⋯ r ‾ ) ∑ i = l r ( x i − x l ⋯ r ‾ ) 2 \dfrac{\sum_{i=l}^r (x_i-\overline{x_{l\cdots r}})(y_i-\overline{y_{l\cdots r}})}{\sum_{i=l}^r (x_i-\overline{x_{l\cdots r}})^2} ∑i=lr(xi−xl⋯r)2∑i=lr(xi−xl⋯r)(yi−yl⋯r),保证分母不为 0 0 0.
- add ( l , r , s , t ) \operatorname{add}(l,r,s,t) add(l,r,s,t):对所有 i ∈ [ l , r ] i \in [l,r] i∈[l,r] 执行 x i ← x i + s , y i ← y i + t x_i \leftarrow \textcolor{red}{x_i} + s, \;y_i \leftarrow \textcolor{red}{y_i} + t xi←xi+s,yi←yi+t.
- modify ( l , r , s , t ) \operatorname{modify}(l,r,s,t) modify(l,r,s,t):对所有 i ∈ [ l , r ] i \in [l,r] i∈[l,r] 执行 x i ← i + s , y i ← i + t x_i \leftarrow \textcolor{red}{i} + s, \;y_i \leftarrow \textcolor{red}{i} + t xi←i+s,yi←i+t.
Limitations
1
≤
n
,
m
≤
1
0
5
1 \le n,m \le 10^5
1≤n,m≤105
∣
s
∣
,
∣
t
∣
≤
1
0
9
|s|,|t| \le 10^9
∣s∣,∣t∣≤109
0
≤
∣
x
i
∣
,
∣
y
i
∣
≤
1
0
5
0 \le |x_i|,|y_i| \le 10^5
0≤∣xi∣,∣yi∣≤105
1
s
,
125
MB
1\text{s},125\text{MB}
1s,125MB
Solution
发现要求的式子难以维护,考虑化简,得到
∑
x
i
y
i
−
∑
x
i
∑
y
i
r
−
l
+
1
∑
x
i
2
−
(
∑
x
i
)
2
r
−
l
+
1
\dfrac{\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}}
∑xi2−r−l+1(∑xi)2∑xiyi−r−l+1∑xi∑yi(过程不好打所以省略)。
现在只需维护
∑
x
i
,
∑
y
i
,
∑
x
i
2
,
∑
x
i
y
i
\sum x_i,\;\sum y_i, \; \sum x_i^2,\; \sum x_iy_i
∑xi,∑yi,∑xi2,∑xiyi,可以上线段树。
考虑 pushdown
如何写,发现后两个不好搞,同样化简式子:
- ∑ ( x i + s ) ( y i + t ) = ∑ x i y i + s ∑ y i + t ∑ x i + s t ( 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) ∑(xi+s)(yi+t)=∑xiyi+s∑yi+t∑xi+st(r−l+1)
- ∑ ( x i + s ) 2 = ∑ x i 2 + 2 s ∑ x i + s 2 ( r − l + 1 ) \sum (x_i+s)^2=\sum x^2_i+2s\sum x_i+s^2(r-l+1) ∑(xi+s)2=∑xi2+2s∑xi+s2(r−l+1)
然后写的时候注意顺序!!
还需要一个
x
i
←
i
,
y
i
←
i
x_i \leftarrow i,y_i \leftarrow i
xi←i,yi←i 的标记,写的时候需要用公式
1
2
+
2
2
+
⋯
+
n
2
=
n
(
n
+
1
)
(
2
n
+
1
)
6
1^2+2^2+\cdots+n^2=\dfrac{n(n+1)(2n+1)}{6}
12+22+⋯+n2=6n(n+1)(2n+1)。
剩下的不必多说,和普通的是一样的。
注意全部要开 double
因为可能爆 long long
。
Code
4.74 KB , 1.21 s , 14.11 MB (in total, C++ 20 with O2) 4.74\text{KB},1.21\text{s},14.11\text{MB} \; \texttt{(in total, C++ 20 with O2)} 4.74KB,1.21s,14.11MB(in total, C++ 20 with O2)
// Problem: P3707 [SDOI2017] 相关分析
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3707
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
namespace seg_tree {
struct Node {
int l, r;
f8 sum_x, sum_y, sum_xx, sum_xy, tag_x, tag_y;
bool cover;
};
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
inline f8 sqsum(f8 a) { return a * (a + 1) * (2 * a + 1) / 6; }
struct SegTree {
vector<Node> tr;
inline SegTree() {}
inline SegTree(const vector<f8>& x, const vector<f8>& y) {
const int n = x.size();
tr.resize(n << 1);
build(0, 0, n - 1, x, y);
}
inline void merge(Node& res, const Node& le, const Node& ri) {
res.sum_x = le.sum_x + ri.sum_x;
res.sum_y = le.sum_y + ri.sum_y;
res.sum_xx = le.sum_xx + ri.sum_xx;
res.sum_xy = le.sum_xy + ri.sum_xy;
}
inline void pushup(int u, int mid) { merge(tr[u], tr[ls(mid)], tr[rs(mid)]); }
void build(int u, int l, int r, const vector<f8>& x, const vector<f8>& y) {
tr[u].l = l, tr[u].r = r;
if (l == r) {
tr[u].sum_x = x[l];
tr[u].sum_y = y[l];
tr[u].sum_xx = x[l] * x[l];
tr[u].sum_xy = x[l] * y[l];
return;
}
const int mid = (l + r) >> 1;
build(ls(mid), l, mid, x, y);
build(rs(mid), mid + 1, r, x, y);
pushup(u, mid);
}
inline void fix(int u) {
const f8 lef = tr[u].l, rig = tr[u].r;
tr[u].tag_x = tr[u].tag_y = 0;
tr[u].cover = true;
tr[u].sum_x = tr[u].sum_y = (lef + rig + 2) * (rig - lef + 1) / 2;
tr[u].sum_xx = tr[u].sum_xy = sqsum(rig + 1) - sqsum(lef);
}
inline void apply(int u, f8 tag_x, f8 tag_y) {
const int len = tr[u].r - tr[u].l + 1;
tr[u].tag_x += tag_x;
tr[u].tag_y += tag_y;
tr[u].sum_xy += tag_y * tr[u].sum_x + tag_x * tr[u].sum_y + tag_x * tag_y * len;
tr[u].sum_xx += 2 * tag_x * tr[u].sum_x + tag_x * tag_x * len;
tr[u].sum_x += tag_x * len;
tr[u].sum_y += tag_y * len;
}
void pushdown(int u, int mid) {
if (tr[u].cover) {
fix(ls(mid)), fix(rs(mid));
tr[u].cover = false;
}
apply(ls(mid), tr[u].tag_x, tr[u].tag_y);
apply(rs(mid), tr[u].tag_x, tr[u].tag_y);
tr[u].tag_x = tr[u].tag_y = 0;
}
void add(int u, int l, int r, f8 x, f8 y) {
if (l <= tr[u].l && tr[u].r <= r) return apply(u, x, y);
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (l <= mid) add(ls(mid), l, r, x, y);
if (r > mid) add(rs(mid), l, r, x, y);
pushup(u, mid);
}
void update(int u, int l, int r, f8 x, f8 y) {
if (l <= tr[u].l && tr[u].r <= r) return (fix(u), apply(u, x, y));
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (l <= mid) update(ls(mid), l, r, x, y);
if (r > mid) update(rs(mid), l, r, x, y);
pushup(u, mid);
}
Node query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u];
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (r <= mid) return query(ls(mid), l, r);
if (l > mid) return query(rs(mid), l, r);
Node res, le = query(ls(mid), l, r), ri = query(rs(mid), l, r);
return (merge(res, le, ri), res);
}
inline void range_add(int l, int r, f8 s, f8 t) { add(0, l, r, s, t); }
inline void range_set(int l, int r, f8 s, f8 t) { update(0, l, r, s, t); }
inline f8 range_slope(int l, int r) {
Node res = query(0, l, r);
const int len = r - l + 1;
f8 num = res.sum_xy - res.sum_x * res.sum_y / len;
f8 den = res.sum_xx - res.sum_x * res.sum_x / len;
return num / den;
}
};
}
using seg_tree::SegTree;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d %d", &n, &m);
vector<f8> x(n), y(n);
for (int i = 0; i < n; i++) scanf("%lf", &x[i]);
for (int i = 0; i < n; i++) scanf("%lf", &y[i]);
SegTree sgt(x, y);
for (int i = 0, op, l, r; i < m; i++) {
scanf("%d %d %d", &op, &l, &r), l--, r--;
if (op == 1) printf("%.10lf\n", sgt.range_slope(l, r));
else if (op == 2) {
f8 s, t; scanf("%lf %lf", &s, &t);
sgt.range_add(l, r, s, t);
}
else {
f8 s, t; scanf("%lf %lf", &s, &t);
sgt.range_set(l, r, s, t);
}
};
return 0;
}