• NOIP“对偶”题:还教室


    先说一下思路:

    方差可以经过恒等变形变成

    x12 + x22 + ... + xn2 + 2a(x1 + x2 + ... + xn) + na2

    所以维护平方和、连续和即可

    平均数我就不再推了……

    天哪我连线段树都能写错!

    写篇随笔记录一下我的易错点,顺便与大家交流一下……

    void maintain(int L, int R, int o) {
        int M = L + R >> 1, lc = o << 1, rc = lc | 1, ln = M - L + 1, rn = R - M;
        sqrv[o] = sqrv[lc] + (addv[lc] * sumv[lc] << 1) + ln * addv[lc] * addv[lc] + sqrv[rc] + (addv[rc] * sumv[rc] << 1) + rn * addv[rc] * addv[rc];
        sumv[o] = sumv[lc] + addv[lc] * ln + sumv[rc] + addv[rc] * rn;
        return ;
    }

    在maintain函数中,须注意

    sumv[o] = sumv[lc] + addv[lc] * ln + sumv[rc] + addv[rc] * rn;

    不能偷懒,写成下面这样是错误的(想一想,为什么)

    sumv[o] = sumv[lc] + sumv[rc] + addv[o] * (R - L + 1);

    我解释一下:这样会将每段区间自己的addv[o]加上,那么query函数if(ql <= L && R <= qr)之中就不能加上add += addv[o]这句话了

    void query(int L, int R, int o, LL add) {
        if(ql <= L && R <= qr) {
            add += addv[o]; int n = R - L + 1;
            _sum += sumv[o] + add * n;
            _sqr += sqrv[o] + (add * sumv[o] << 1) + n * add * add;
        } else {
            int M = L + R >> 1, lc = o << 1, rc = lc | 1;
            if(ql <= M) query(L, M, lc, add + addv[o]);
            if(qr > M) query(M+1, R, rc, add + addv[o]);
        }
        return ;
    }

    (这是个人写线段树的习惯,习惯不一样的话易错点不再适用)

    完整代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstdlib>
    using namespace std;
    
    int read() {
        int x = 0, f = 1; char c = getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
        return x * f;
    }
    
    #define LL long long
    #define maxn 100010
    struct Fraction {
        LL a, b;
        
        LL gcd(LL a, LL b) {
            return !b ? a : gcd(b, a % b);
        }
        
        Fraction maintain() {
            if(!a) { b = 1; return *this; }
            LL t = gcd(a, b); a /= t; b /= t;
            return *this;
        }
        
        Fraction operator - (const Fraction& t) const {
            Fraction ans = (Fraction){ a * t.b - t.a * b, b * t.b };
            return ans.maintain();
        }
        Fraction operator -= (const Fraction& t) {
            *this = *this - t;
            return *this;
        }
        
        void print() {
            printf("%lld/%lld
    ", a, b);
            return ;
        }
    } ;
    LL sumv[maxn*3], sqrv[maxn*3], addv[maxn*3], A[maxn];
    
    void maintain(int L, int R, int o) {
        int M = L + R >> 1, lc = o << 1, rc = lc | 1, ln = M - L + 1, rn = R - M;
        sqrv[o] = sqrv[lc] + (addv[lc] * sumv[lc] << 1) + ln * addv[lc] * addv[lc] + sqrv[rc] + (addv[rc] * sumv[rc] << 1) + rn * addv[rc] * addv[rc];
        sumv[o] = sumv[lc] + addv[lc] * ln + sumv[rc] + addv[rc] * rn;
        return ;
    }
    
    void build(int L, int R, int o) {
        if(L == R){ sumv[o] = A[L]; sqrv[o] = A[L] * A[R]; }
        else {
            int M = L + R >> 1, lc = o << 1, rc = lc | 1;
            build(L, M, lc);
            build(M+1, R, rc);
            maintain(L, R, o);
        }
        return ;
    }
    
    int ql, qr; LL v;
    void update(int L, int R, int o) {
        if(ql <= L && R <= qr) addv[o] += v;
        else {
            int M = L + R >> 1, lc = o << 1, rc = lc | 1;
            addv[lc] += addv[o]; addv[rc] += addv[o]; addv[o] = 0;
            if(ql <= M) update(L, M, lc);
            if(qr > M) update(M+1, R, rc);
            maintain(L, R, o);
        }
        return ;
    }
    
    LL _sum, _sqr;
    void query(int L, int R, int o, LL add) {
        if(ql <= L && R <= qr) {
            add += addv[o]; int n = R - L + 1;
            _sum += sumv[o] + add * n;
            _sqr += sqrv[o] + (add * sumv[o] << 1) + n * add * add;
        } else {
            int M = L + R >> 1, lc = o << 1, rc = lc | 1;
            if(ql <= M) query(L, M, lc, add + addv[o]);
            if(qr > M) query(M+1, R, rc, add + addv[o]);
        }
        return ;
    }
    
    int main() {
        int n = read(), m = read();
        for(int i = 1; i <= n; i++) A[i] = read();
        build(1, n, 1);
        while(m--) {
            int tp = read(); ql = read(); qr = read();
            if(tp == 1) {
                v = read(); update(1, n, 1);
            } else {
                _sum = _sqr = 0;
                query(1, n, 1, 0);
                Fraction ans; LL tn = qr - ql + 1;
                if(tp == 2) { // average
                    ans = (Fraction){ _sum, tn };
                    ans.maintain();
                } else { // variance
                    ans = (Fraction){ _sqr * tn - _sum * _sum, tn * tn };
                    ans.maintain();
                }
                ans.print();
            }
        }
        
        return 0;
    }
  • 相关阅读:
    BZOJ 1185 [HNOI2007]最小矩形覆盖 ——计算几何
    BZOJ 1007 [HNOI2008]水平可见直线 ——计算几何
    BZOJ 1069 [SCOI2007]最大土地面积 ——计算几何
    BZOJ 2829 信用卡凸包 ——计算几何
    BZOJ 2300 [HAOI2011]防线修建 ——计算几何
    BZOJ 1027 [JSOI2007]合金 ——计算几何
    BZOJ 1043 [HAOI2008]下落的圆盘 ——计算几何
    BZOJ 1294 [SCOI2009]围豆豆Bean ——计算几何
    BZOJ 1043 [HAOI2008]下落的圆盘 ——计算几何
    radius服务器搭建
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/4878366.html
Copyright © 2020-2023  润新知