1. 程式人生 > 實用技巧 >[SDOI2017]相關分析 題解

[SDOI2017]相關分析 題解

題意

給定兩個陣列$x, y$,有三種操作

  • 給定$l, r$,令$\overline x = \frac{1}{r - l + 1}\sum_{i = l}^r x_i,\overline y= \frac{1}{r - l + 1}\sum_{i = l}^r y_i$,即該陣列$[l,r]$間數的平均數,求$$\frac{\sum_{i=l}^r(x_i-\overline x)(y_i-\overline y)}{\sum_{i=l}^r (x_i-\overline x) ^2}$$
  • 給定$l,r,s,t$,對任意$i\in[l,r],x_i = x_i + s, y_i = y_i + t$
  • 給定$l,r,s,t$,對任意$i\in[l,r],x_i = i + s, y_i = i+t$

Sol

化簡一波式子

$$\frac{\sum_{i=l}^r(x_i-\overline x)(y_i-\overline y)}{\sum_{i=l}^r (x_i-\overline x) ^2}$$

拆開乘積與平方,此處記$\sum_{i=l}^r$為$\sum$

$$=\frac{\sum x_iy_i - \sum \overline x y_i - \sum\overline y x_i + (r-l+1)\overline x\overline y}{\sum x_i^2 - 2\sum\overline x x_i+(r-l+1)\overline x_i^2}$$

將$\overline x,\overline y$代入

$$=\frac{\sum x_i y_i - \frac{\sum x_i \sum y_i}{r-l+1} - \frac{\sum x_i \sum y_i}{r-l+1}+(r-l+1)\frac{\sum x_i}{r-l+1}\frac{\sum y_i}{r-l+1}}{\sum x_i^2 - \frac{\sum x_i}{r-l+1}-(r-l+1)\frac{\sum x_i}{r-l+1}\frac{\sum x_i}{r-l+1}}$$

化簡一波

$$=\frac{\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}}$$

所以我們要維護$4$個東西:$\sum x_i, \sum y_i,\sum x_i^2, \sum x_iy_i$

$1$操作

直接按照推出來的式子進行作答即可

$2$操作

$\sum (x_i + s) ^2 = \sum x_i^2 + 2s\sum x_i+s^2 (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)$

$\sum (x_i+s)=\sum x_i+s(r-l+1)$

$\sum(y_i+t)=\sum y_i+t(r-l+1)$

下面兩項的值會被上面兩項在修改時引用,所以先修改上面兩項。

$3$操作

前置公式:$1^2+2^2+...+n^2=\frac{n(n+1)(2n+1)}{6}$

我們把操作拆分成兩步

  • 對於任意$i\in[l,r],x_i = y_i = i$
  • 對於任意$i\in[l,r],x_i=x_i+s,y_i=y_i+t$

對於第二步,用上面的方法即可

對於第一步,我們看每一個要維護的值是多少

$\sum i^2 = \frac{r(r+1)(2r+1)-l(l-1)(2l-1)}{6}$

$\sum i=\frac{(r-l+1)(r+l)}{2}$

$O(1)$求出即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
double x[100005], y[100005];
double A[400005], B[400005], C[400005], D[400005], addS[400005], addT[400005], covS[400005], covT[400005];
void pushup(int o) {
    A[o] = A[o << 1] + A[o << 1 | 1];
    B[o] = B[o << 1] + B[o << 1 | 1];
    C[o] = C[o << 1] + C[o << 1 | 1];
    D[o] = D[o << 1] + D[o << 1 | 1];
}
void build(int o, int l, int r) {
    covS[o] = covT[o] = 1E9;
    if(l == r) {
        A[o] = x[l] * x[l];
        B[o] = x[l] * y[l];
        C[o] = x[l], D[o] = y[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    pushup(o);
}
void pusha(int o, double aS, double aT, int l, int r) {
    addS[o] += aS, addT[o] += aT;
    A[o] = A[o] + 2 * aS * C[o] + aS * aS * (r - l + 1);
    B[o] = B[o] + aS * D[o] + aT * C[o] + aS * aT * (r - l + 1);
    C[o] = C[o] + aS * (r - l + 1);
    D[o] = D[o] + aT * (r - l + 1);
}
void pushc(int o, double cS, double cT, int l, int r) {
    addS[o] = 0, addT[o] = 0;
    covS[o] = cS, covT[o] = cT;
    A[o] = B[o] = r * (r + 1) * (2 * r + 1) / 6 - l * (l - 1) * (2 * l - 1) / 6;
    C[o] = D[o] = (r - l + 1) * (r + l) / 2;
    pusha(o, cS, cT, l, r);
}
void pushdown(int o, int l, int r) {
    if(covS[o] != 1E9 || covT[o] != 1E9) {
        int mid = (l + r) >> 1;
        pushc(o << 1, covS[o], covT[o], l, mid);
        pushc(o << 1 | 1, covS[o], covT[o], mid + 1, r);
        addS[o] -= covS[o], addT[o] -= covT[o];
        covS[o] = covT[o] = 1E9;
    }
    if(addS[o] || addT[o]) {
        int mid = (l + r) >> 1;
        pusha(o << 1, addS[o], addT[o], l, mid);
        pusha(o << 1 | 1, addS[o], addT[o], mid + 1, r);
        addS[o] = addT[o] = 0;
    }
}
void modify_add(int o, int l, int r, int nl, int nr, double S, double T) {
    if(nl <= l && r <= nr) {
        pusha(o, S, T, l, r);
        return ;
    }
    pushdown(o, l, r);
    int mid = (l + r) >> 1;
    if(nl <= mid)  modify_add(o << 1, l, mid, nl, nr, S, T);
    if(mid < nr)  modify_add(o << 1 | 1, mid + 1, r, nl, nr, S, T);
    pushup(o);
}
void modify_cov(int o, int l, int r, int nl, int nr, double S, double T) {
    if(nl <= l && r <= nr) {
        pushc(o, S, T, l, r);
        return ;
    }
    pushdown(o, l, r);
    int mid = (l + r) >> 1;
    if(nl <= mid)  modify_cov(o << 1, l, mid, nl, nr, S, T);
    if(mid < nr)  modify_cov(o << 1 | 1, mid + 1, r, nl, nr, S, T);
    pushup(o);
}
struct node {
    double A, B, C, D;
    node(double a = 0, double b = 0, double c = 0, double d = 0) {A = a, B = b, C = c, D = d;}
};
node operator + (node X, node Y) {
    node Z;
    Z.A = X.A + Y.A; Z.B = X.B + Y.B;
    Z.C = X.C + Y.C; Z.D = X.D + Y.D;
    return Z;
}
node query(int o, int l, int r, int nl, int nr) {
    if(nl <= l && r <= nr)  return node(A[o], B[o], C[o], D[o]);
    pushdown(o, l, r);
    int mid = (l + r) >> 1; node ans;
    if(nl <= mid)  ans = ans + query(o << 1, l, mid, nl, nr);
    if(mid < nr)  ans = ans + query(o << 1 | 1, mid + 1, r, nl, nr);
    return ans;
}
signed main() {
    int n, m;
    scanf("%lld%lld", &n, &m);
    for(int i = 1; i <= n; i++)  scanf("%lf", &x[i]);
    for(int i = 1; i <= n; i++)  scanf("%lf", &y[i]);
    build(1, 1, n);
    for(int i = 1; i <= m; i++) {
        int opt, l, r; double s, t;
        scanf("%lld%lld%lld", &opt, &l, &r);
        if(opt == 1) {
            node S = query(1, 1, n, l, r);
            printf("%.10lf\n", (S.B - S.C * S.D / (r - l + 1)) / (S.A - S.C * S.C / (r - l + 1)));
        }
        if(opt == 2) {
            scanf("%lf%lf", &s, &t);
            modify_add(1, 1, n, l, r, s, t);
        }
        if(opt == 3) {
            scanf("%lf%lf", &s, &t);
            modify_cov(1, 1, n, l, r, s, t);
        }
    }
}
View Code