线段树大法好啊!

· · 题解

本题解分为 3 部分:

约分方法:分子 $x$、分母 $y$ 同时除以 $\gcd(x,y)$。(不会吧,如果这都不会建议重读小学)。 这里有一个分数结构体,重载了四则运算: ```cpp typedef pair<LL, LL> PII; LL gcd(LL a, LL b) { return (!b) ? (a) : (gcd(b, a % b)); } struct fra { LL x, y; void judge() {//约分 LL gg = gcd(x, y); x /= gg; y /= gg; } fra operator =(pair<LL, LL> p) {//赋值 x = p.first; y = p.second; judge(); return *this; } fra operator +(fra p) {//四则运算(自动约分) LL ny = y * p.y; LL nx = (p.y * x) + (y * p.x); fra tmp = {nx, ny}; tmp.judge(); return tmp; } fra operator -(fra p) { LL ny = y * p.y; LL nx = (p.y * x) - (y * p.x); fra tmp = {nx, ny}; tmp.judge(); return tmp; } fra operator *(fra p) { LL nx = x * p.x; LL ny = y * p.y; fra tmp = {nx, ny}; tmp.judge(); return tmp; } fra operator /(fra p) { fra tmp = {p.y, p.x}; return (*this) * tmp; } fra rec() {//倒数 return {y, x}; } }; ``` $2$.公式推导。这题只要有了公式就很简单了。 - 平均数:设总和为 $sum$,区间长度为 $len$,则平均数 $\bar{a}$ 为 $\dfrac{sum}{len}$。 - 方差:方差不好直接推,我们考虑维护平方和。 case $1$:当区间加 $d$ 时,设原来平方和为 $fs$,统一加 $v$,且原来总值为 $sum$。 则现在有:$\sum^{r}_{i=l} (a_i+v)^2$; 用完全平方公式打开得 $\sum^{r}_{i=l} {a_i^2 + a_i \times v \times 2 + v^2}$。 然后得:$\sum^{r}_{i=l} a_i^2 + 2\times v \times \sum^{r}_{i=l} a_i + \sum^{r}_{i=l} v^2$。 我们用 $fs$ 替换 $\sum^{r}_{i=l}$,然后用 $sum$ 替换 $\sum^{r}_{i=l}$。 得现在平方和是:$fs + 2 \times v \times sum + \sum^{r}_{i=l} v^2$。 我们只需要加 $2 \times v \times sum + \sum^{r}_{i=l} v^2$ 就可以了。 --- case $2$:用平方和计算出方差。这个麻烦一点。 原式 $ = \sum^{r}_{i = l} (a_i - \bar{a})^2$。 用完全平方公式打开得 $\sum^{r}_{i = l} a_i^2 - \sum^{r}_{i=l}2 \times \bar{a} \times a_i+ \sum^{r}_{i=l}\bar{a}^2$。 然后得:$fs - \bar{a} \times 2 \times sum + \sum^{r}_{i=l} \bar{a}^2$。 进一步得:$fs - 2 \times sum \times \bar{a} + \dfrac{sum^2}{r-l+1}$。就好算了。 也就是:$fs - 2 \times sum \times \dfrac{sum}{r - l + 1} + \dfrac{sum^2}{r-l+1}$。 得出:$fs - 2 \times \dfrac{sum^2}{r - l + 1} + \dfrac{sum^2}{r-l+1}$。 别急,马上就推好了! 现在有:$fs - \dfrac{2 \times sum^2}{r-l+1} + \dfrac{sum^2}{r-l+1}$。 为了方便我们写程序,还可以化成:$\dfrac{(r-l+1) \times fs - sum^2}{(r-l+1)^2}$。 现在很方便,不是吗? --- $3$.代码时间! ```cpp #include <bits/stdc++.h> #define R register #define inl inline #define fastios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #define Debug(file) freopen(file".in","r",stdin);freopen(file".out","w",stdout); using namespace std; #define L(u) (u << 1) #define R(u) ((u << 1) | 1) typedef unsigned long long LL; LL f(LL x) { return x * x; } typedef pair<LL, LL> PII; LL gcd(LL a, LL b) { return (!b) ? (a) : (gcd(b, a % b)); } struct fra { LL x, y; void judge() { LL gg = gcd(x, y); x /= gg; y /= gg; } fra operator =(pair<LL, LL> p) { x = p.first; y = p.second; judge(); return *this; } fra operator +(fra p) { LL ny = y * p.y; LL nx = (p.y * x) + (y * p.x); fra tmp = {nx, ny}; tmp.judge(); return tmp; } fra operator -(fra p) { LL ny = y * p.y; LL nx = (p.y * x) - (y * p.x); fra tmp = {nx, ny}; tmp.judge(); return tmp; } fra operator *(fra p) { LL nx = x * p.x; LL ny = y * p.y; fra tmp = {nx, ny}; tmp.judge(); return tmp; } fra operator /(fra p) { fra tmp = {p.y, p.x}; return (*this) * tmp; } fra rec() { return {y, x}; } }; istream &operator >>(istream &i, fra &f) { scanf("%llu/%llu", &f.x, &f.y); return i; } ostream &operator <<(ostream &o, fra f) { printf("%llu/%llu", f.x, f.y); return o; } ``` ```cpp /*----------FRACTION-----------PART------------*/ const int N = 1e5 + 5; struct node { int l, r; LL ps, sum; LL add; } tr[N * 4]; LL n, m, a[N]; void pushup(int u) { tr[u].ps = tr[u << 1].ps + tr[u << 1 | 1].ps; tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum; } void pushdown(int u) { node &l = tr[u << 1]; node &r = tr[u << 1 | 1]; node &now = tr[u]; l.add += now.add; r.add += now.add; l.ps += (f(now.add) * (l.r - l.l + 1)) + (2ll * l.sum * now.add); r.ps += (f(now.add) * (r.r - r.l + 1)) + (2ll * r.sum * now.add); l.sum += (l.r - l.l + 1ll) * now.add; r.sum += (r.r - r.l + 1ll) * now.add; now.add = 0; } void build(int u, int l, int r) { if (l == r) tr[u] = {l, r, f(a[l]), a[l],0}; else { int mid = l + r >> 1; tr[u] = {l, r, 0, 0, 0}; build(L(u), l, mid); build(R(u), mid + 1, r); pushup(u); } } void modify(int u, int l, int r, LL v) { if (l <= tr[u].l && tr[u].r <= r) { tr[u].add += v; tr[u].ps += (f(v) * (tr[u].r - tr[u].l + 1)) + (2ll * tr[u].sum * v); tr[u].sum += (tr[u].r - tr[u].l + 1) * v; } else { int mid = (tr[u].l + tr[u].r) >> 1; pushdown(u); if (l <= mid) { modify(u << 1, l, r, v); } if (r > mid) { modify(u << 1 | 1, l, r, v); } pushup(u); } } LL query_sum(int u, int l, int r) { if (l <= tr[u].l && tr[u].r <= r) { return tr[u].sum; } else { pushdown(u); int mid = tr[u].l + tr[u].r >> 1; LL ans = 0; if (l <= mid) ans = query_sum(u << 1, l, r); if (r > mid) ans += query_sum(u << 1 | 1, l, r); return ans; } } LL query_fs(int u, int l, int r) { if (l <= tr[u].l && tr[u].r <= r) { return tr[u].ps; } else { pushdown(u); int mid = tr[u].l + tr[u].r >> 1; LL ans = 0; if (l <= mid) ans += query_fs(u << 1, l, r); if (r > mid) ans += query_fs(u << 1 | 1, l, r); return ans; } } ``` ```cpp /*----------SEGMENT----TREE----PART------------*/ int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++) scanf("%llu", &a[i]); build(1,1,n); for (int i = 0; i < m; i ++) { int op, l, r;LL d; scanf("%d%d%d", &op, &l, &r); if (op == 1) { scanf("%llu", &d); modify(1, l, r, d); } if (op == 2) { fra tmp = {query_sum(1, l, r), (r - l + 1)}; tmp.judge(); cout << tmp << endl; } if (op == 3) { LL sum = query_sum(1,l,r); LL pfs = query_fs(1,l,r); LL len = r-l+1; //printf("pfs:%llu sum:%llu\n",pfs,sum); fra ans = {len*pfs-sum*sum,len*len}; ans.judge(); cout << ans << endl; } } return 0; } ```