bzoj 4821 [Sdoi2017]相关分析 线段树

题面

题目传送门

解法

文化课烂了之后回来写数据结构……

  • 首先,我们明显可以将分子和分母分开来算。
  • 对于分子,我们可以这样展开: ( 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 ,然后我们可以发现,可以通过维护 x i y i \sum x_iy_i x i \sum x_i y i \sum y_i 来实现
  • 对于分母,我们可以这样展开: ( 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 ,然后可以发现,可以通过维护 x i 2 \sum x_i^2 x i \sum x_i 来实现。
  • 然后问题就是如果存在修改会出现什么情况。
  • 先单独考虑操作 2 2 ,分子上的 x i y i \sum x_iy_i 会变成 ( 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 ,影响并不是很大。分母上考虑如何修改 x i 2 \sum x_i^2 ,可以变成 ( 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 来实现。
  • 这样,我们就可以轻松自如地处理操作 2 2
  • 然后考虑如何处理操作 3 3
  • 分子上 x i y i \sum x_iy_i 会变成 s t + ( s + t ) i + i 2 \sum st+(s+t)\sum i+\sum i^2 ,维护起来也十分方便。分母上就比较简单了,就是连续一段的平方和或者是等差数列求和。
  • 那么,我们不妨用一棵线段树来维护这个过程,中间需要打两个标记,一个为 ( a d d s , a d d t ) (add_s,add_t) 表示操作 2 2 ,一个为 ( s e t s , s e t t ) (set_s,set_t) 表示操作 3 3 。下传标记的时候注意一下标记的先后顺序问题就可以了。
  • 时间复杂度: O ( m log n ) O(m\log n)

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/emmmmmmmmm/article/details/86665190