loj2005「SDOI2017」相关分析

很明显是要推公式啊,然后用线段树维护。
以下我们将 ∑ i = l r \sum_{i=l}^r i=lr看成 ∑ \sum
把操作1的公式化简一下,就可以得到需要维护的有
∑ x i \sum x_i xi

∑ y i \sum y_i yi

∑ x i ∗ y i \sum x_i*y_i xiyi

∑ x i 2 \sum x_i^2 xi2

这四种。
然后用上求和公式和平方和公式就可以很容易的得到操作二和操作三分别是:
(操作二)
∑ x i + = ( r − l + 1 ) ∗ S \sum x_i+=(r-l+1)*S xi+=(rl+1)S

∑ y i + = ( r − l + 1 ) ∗ T \sum y_i+=(r-l+1)*T yi+=(rl+1)T

∑ x i ∗ y i + = T ∗ ∑ x i + S ∗ ∑ y i + ( r − l + 1 ) ∗ S ∗ T \sum x_i*y_i+=T*\sum x_i+S*\sum y_i+(r-l+1)*S*T xiyi+=Txi+Syi+(rl+1)ST

∑ x i 2 + = 2 ∗ S ∗ ∑ x i + ( r − l + 1 ) ∗ S 2 \sum x_i^2+=2*S*\sum x_i+(r-l+1)*S^2 xi2+=2Sxi+(rl+1)S2

(操作三)
∑ x i = ( r − l + 1 ) ∗ S + ( r − l + 1 ) ( l + r ) 2 \sum x_i=(r-l+1)*S+\frac{(r-l+1)(l+r)}{2} xi=(rl+1)S+2(rl+1)(l+r)

∑ y i = ( r − l + 1 ) ∗ T + ( r − l + 1 ) ( l + r ) 2 \sum y_i=(r-l+1)*T+\frac{(r-l+1)(l+r)}{2} yi=(rl+1)T+2(rl+1)(l+r)

∑ x i ∗ y i = ( r − l + 1 ) ∗ S ∗ T + ( S + T ) ( l + r ) ( r − l + 1 ) 2 + r ( r + 1 ) ( 2 r + 1 ) 6 − l ( l − 1 ) ( 2 l − 1 ) 6 \sum x_i*y_i=(r-l+1)*S*T+\frac{(S+T)(l+r)(r-l+1)}{2}+\frac{r(r+1)(2r+1)}{6}-\frac{l(l-1)(2l-1)}{6} xiyi=(rl+1)ST+2(S+T)(l+r)(rl+1)+6r(r+1)(2r+1)6l(l1)(2l1)

∑ x i 2 = ( r − l + 1 ) ∗ S 2 + S ∗ ( l + r ) ( r − l + 1 ) + r ( r + 1 ) ( 2 r + 1 ) 6 − l ( l − 1 ) ( 2 l − 1 ) 6 \sum x_i^2=(r-l+1)*S^2+S*(l+r)(r-l+1)+\frac{r(r+1)(2r+1)}{6}-\frac{l(l-1)(2l-1)}{6} xi2=(rl+1)S2+S(l+r)(rl+1)+6r(r+1)(2r+1)6l(l1)(2l1)

参考代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
inline int read() {
	int x = 0, f = 0; char s = getchar();
	while (!isdigit(s)) f |= s=='-', s = getchar();
	while ( isdigit(s)) x = x * 10 + s - 48, s = getchar();
	return f ? -x : x;
}
const int N = 1e5 + 5, M = 4e5 + 5;
int n, m, X[N], Y[N], QAQ = 1;
struct cyx {
    double sumX, sumY, sumXY, sumX2, addX, addY,
        firX, firY; bool cn;
    int l, r, lc, rc;
} t[M];
struct clb {
    double sumX, sumY, sumXY, sumX2;
    friend inline clb operator + (clb a, clb b) {
        clb res; res.sumX = a.sumX + b.sumX;
        res.sumY = a.sumY + b.sumY;
        res.sumX2 = a.sumX2 + b.sumX2;
        res.sumXY = a.sumXY + b.sumXY;
        return res;
    }
};
inline double sqr(const double x) {return x * x;}
inline double sumx2(double l, double r) {
    return 1.0 * r * (r + 1) * (2.0 * r + 1) / 6.0
        - 1.0 * l * (l - 1) * (2.0 * l - 1) / 6.0;
}
inline void downdate(int x) {
    int lc = t[x].lc, rc = t[x].rc;
    if (t[x].cn) {
        t[lc].firX = t[x].firX;
        t[rc].firX = t[x].firX;
        t[lc].cn = t[rc].cn = 1; t[x].cn = 0;
        t[lc].addX = t[rc].addX  = 0;
        t[lc].firY = t[x].firY;
        t[rc].firY = t[x].firY;
        t[lc].cn = t[rc].cn = 1; t[x].cn = 0;
        t[lc].addY = t[rc].addY = 0;
    }
    t[lc].addX += t[x].addX; t[rc].addX += t[x].addX; t[x].addX = 0;
    t[lc].addY += t[x].addY; t[rc].addY += t[x].addY; t[x].addY = 0;
}
inline void upt(int x) {
    int lc = t[x].lc, rc = t[x].rc, l = t[x].l, r = t[x].r;
    double x1, y1, xy1, x21, x2, y2, xy2, x22; int mid = l + r >> 1;
    x1 = t[lc].sumX; x2 = t[rc].sumX;
    y1 = t[lc].sumY; y2 = t[rc].sumY;
    x21 = t[lc].sumX2; x22 = t[rc].sumX2;
    xy1 = t[lc].sumXY; xy2 = t[rc].sumXY;
    x21 += 2.0 * x1 * t[lc].addX + t[lc].addX * t[lc].addX * (mid - l + 1);
    x22 += 2.0 * x2 * t[rc].addX + t[rc].addX * t[rc].addX * (r - mid);
    xy1 += x1 * t[lc].addY + t[lc].addX * y1 + t[lc].addX * t[lc].addY * (mid - l + 1);
    xy2 += x2 * t[rc].addY + t[rc].addX * y2 + t[rc].addX * t[rc].addY * (r - mid);
    x1 += t[lc].addX * (mid - l + 1); x2 += t[rc].addX * (r - mid);
    y1 += t[lc].addY * (mid - l + 1); y2 += t[rc].addY * (r - mid);
    if (t[lc].cn) {
        double lx = t[lc].firX + t[lc].addX, ly = t[lc].firY + t[lc].addY;
        x21 = 1.0 * (mid - l + 1) * sqr(lx) + lx * (l + mid) *
            (mid - l + 1) + sumx2(l, mid);
        xy1 = 1.0 * lx * ly * (mid - l + 1) + (lx + ly) * (l + mid)
            * (mid - l + 1) / 2.0 + sumx2(l, mid);
        x1 = lx * (mid - l + 1) + 1.0 * (l + mid) * (mid - l + 1) / 2.0;
        y1 = ly * (mid - l + 1) + 1.0 * (l + mid) * (mid - l + 1) / 2.0;
    }
    if (t[rc].cn) {
        double rx = t[rc].firX + t[rc].addX, ry = t[rc].firY + t[rc].addY;
        x22 = 1.0 * (r - mid) * sqr(rx) + rx * (mid + 1 + r) *
            (r - mid) + sumx2(mid + 1, r);
        xy2 = 1.0 * rx * ry * (r - mid) + (rx + ry) * (mid + 1 + r)
            * (r - mid) / 2.0 + sumx2(mid + 1, r);
        x2 = rx * (r - mid) + 1.0 * (mid + 1 + r) * (r - mid) / 2.0;
        y2 = ry * (r - mid) + 1.0 * (mid + 1 + r) * (r - mid) / 2.0;
    }
    t[x].sumX = x1 + x2; t[x].sumY = y1 + y2;
    t[x].sumXY = xy1 + xy2; t[x].sumX2 = x21 + x22;
}
inline void build(int l, int r, int p) {
    t[p].l = l; t[p].r = r;
    if (l == r) {
        t[p].sumX = X[l]; t[p].sumY = Y[l];
        t[p].sumXY = t[p].sumX * t[p].sumY;
        t[p].sumX2 = t[p].sumX * t[p].sumX;
        return;
    }
    int p2 = (t[p].lc = ++QAQ), p3 = (t[p].rc = ++QAQ);
    int mid = l + r >> 1; build(l, mid, p2); build(mid + 1, r, p3);
    t[p].sumX = t[p2].sumX + t[p3].sumX;
    t[p].sumY = t[p2].sumY + t[p3].sumY;
    t[p].sumXY = t[p2].sumXY + t[p3].sumXY;
    t[p].sumX2 = t[p2].sumX2 + t[p3].sumX2;
}
inline void change(int s, int e, int Si, int Ti, int p) {
    int l = t[p].l, r = t[p].r;
    if (l == s && r == e) {
        t[p].addX += 1.0 * Si; t[p].addY += 1.0 * Ti;
        return;
    }
    int mid = l + r >> 1, p2 = t[p].lc, p3 = t[p].rc; downdate(p);
    if (e <= mid) change(s, e, Si, Ti, p2);
    else if (s >= mid + 1) change(s, e, Si, Ti, p3);
    else change(s, mid, Si, Ti, p2), change(mid + 1, e, Si, Ti, p3);
    upt(p);
}
inline void modify(int s, int e, int Si, int Ti, int p) {
    int l = t[p].l, r = t[p].r;
    if (t[p].l == s && t[p].r == e) {
        t[p].cn = 1; t[p].firX = 1.0 * Si; t[p].firY = 1.0 * Ti; 
        t[p].addX = t[p].addY = 0;
        return;
    }
    int mid = l + r >> 1, p2 = t[p].lc, p3 = t[p].rc; downdate(p);
    if (e <= mid) modify(s, e, Si, Ti, p2);
    else if (s >= mid + 1) modify(s, e, Si, Ti, p3);
    else modify(s, mid, Si, Ti, p2), modify(mid + 1, e, Si, Ti, p3);
    upt(p);
}
inline clb ask(int s, int e, int p) {
    clb res; int l = t[p].l, r = t[p].r;
    if (l == s && r == e) {
        double x, y;
        if (t[p].cn) {
            x = t[p].firX + t[p].addX; y = t[p].firY + t[p].addY;
            res.sumX = x * (r - l + 1) +
                1.0 * (l + r) * (r - l + 1)
                / 2.0;
            res.sumY = y * (r - l + 1) +
                1.0 * (l + r) * (r - l + 1)
                / 2.0;
            res.sumXY = x * y * (r - l + 1) +
                1.0 * (x + y) * (l + r) * (r - l + 1)
                / 2.0 + sumx2(l, r);
            res.sumX2 = sqr(x) * (r - l + 1) +
                x * (l + r) * (r - l + 1) + sumx2(l, r);
            return res;
        }
        res.sumX = t[p].sumX + t[p].addX * (r - l + 1);
        res.sumY = t[p].sumY + t[p].addY * (r - l + 1);
        res.sumXY = t[p].sumXY + t[p].sumX * t[p].addY
            + t[p].sumY * t[p].addX + t[p].addX * t[p].addY * (r - l + 1);
        res.sumX2 = t[p].sumX2 + 2.0 * t[p].addX * t[p].sumX
            + sqr(t[p].addX) * (r - l + 1);
        return res;
    }
    int mid = l + r >> 1, p2 = t[p].lc, p3 = t[p].rc; downdate(p);
    if (e <= mid) res = ask(s, e, p2);
    else if (s >= mid + 1) res = ask(s, e, p3);
    else res = ask(s, mid, p2) + ask(mid + 1, e, p3);
    return upt(p), res;
}
inline double trans(int l, int r, clb res) {
    double x = res.sumX, y = res.sumY, x2 = res.sumX2, xy = res.sumXY;
    return (xy - x * y / (r - l + 1)) / (x2 - x * x / (r - l + 1));
}
int main() {
    int i, op, x, y, u, v; n = read(); m = read();
    for (i = 1; i <= n; i++) X[i] = read();
    for (i = 1; i <= n; i++) Y[i] = read();
    build(1, n, 1);
    while (m--) {
        op = read(); if (op == 2) {
            x = read(); y = read(); u = read(); v = read();
            change(x, y, u, v, 1);
        }
        else if (op == 3) {
            x = read(); y = read(); u = read(); v = read();
            modify(x, y, u, v, 1);
        }
        else {
            x = read(); y = read();
            printf("%.10lf\n", trans(x, y, ask(x, y, 1)));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值