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\n", 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;
}
posted @ 2015-10-14 19:01  xjr01  阅读(257)  评论(1编辑  收藏  举报