NOJ1560---Let Slimes Grow Up(线段树)

问题描述
You know 8Mao has his own Slime Team. But he soon found that let the Slimes stand in a line and make them from low to high is a such stupid thing since the Slimes are so f[bi][bi]king stupid!
As a result, 8Mao decided to give up.
But 8Mao still want his Slime Team be beautiful. So he got up another idea, let his Slimes grow up. He got some medicine that can make the Slimes in the line get higher. But only can let continuous Slimes.
8Mao thought that the variance of the heights of Slimes in the line is smaller, the Slime Team is more beautiful.
You have to help 8Mao to calculate out the variance of Slimes in a continuous sequence.
输入
This problem contains several cases, ends with EOF.
The first line of each case contains 2 integers N and M which N indicates the number of Slimes and the number of operations.
Next line contains the heights of each Slimes ordered from 0 ~ N - 1. (0 < height <= 100, 000)
Then M lines followed. Each line indicates one operation.
If the operator is “1”, then follows 3 integers A, B and C which indicate the start number of the Slimes and the end number of the Slimes and the heights the Slimes between A and B will increase.
If the operator is “2”, then follows 2 integers A and B, you have to calculate out the variance of heights between Slime A and Slime B.
输出
For each operator “2”, you should output the variance. (The answer should be formatted to integer)
样例输入

5 3
1 4 3 2 5
2 0 4
1 1 2 2
2 0 4

样例输出

2
3

提示

来源

cjl

操作

要求区间内的方差,把方差公式转换以后,变成维护区间和和区间平方和,然后线段树乱搞下就行,
这题是去年校赛的,可惜那时太弱根本不会

/*************************************************************************
    > File Name: NOJ1560.cpp
    > Author: ALex
    > Mail: zchao1995@gmail.com 
    > Created Time: 2015年04月16日 星期四 20时22分13秒
 ************************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>

using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

static const int N = 100100;
struct node
{
    int l, r;
    LL sum;
    LL sumsum;
    LL add;
}tree[N << 2];

void build(int p, int l, int r)
{
    tree[p].l = l;
    tree[p].r = r;
    tree[p].add = 0;
    if (l == r)
    {
        scanf("%lld", &tree[p].sum);
        tree[p].sumsum = tree[p].sum * tree[p].sum;
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
    tree[p].sumsum = tree[p << 1].sumsum + tree[p << 1 | 1].sumsum;
}

void pushdown(int p)
{
    if (tree[p].add)
    {
        tree[p << 1].add += tree[p].add;
        tree[p << 1 | 1].add += tree[p].add;
        int m = tree[p << 1].r - tree[p << 1].l + 1; //左子树长度
        LL use = tree[p].add;
        LL sum1 = tree[p << 1].sum;
        tree[p << 1].sum += use * m;
        tree[p << 1].sumsum += m * use * use + 2 * use * sum1;
        LL sum2 = tree[p << 1 | 1].sum;
        m = tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1;
        tree[p << 1 | 1].sum += use * m;
        tree[p << 1 | 1].sumsum += m * use * use + 2 * use * sum2;
        tree[p].add = 0;
    }
}

void update(int p, int l, int r, LL val)
{
    if (tree[p].l == l && r == tree[p].r)
    {
        tree[p].add += val;
        int m = r - l + 1;
        LL sum = tree[p].sum;
        tree[p].sum += m * val;
        tree[p].sumsum += val * val * m + 2 * val * sum;
        return;
    }
    pushdown(p);
    int mid = (tree[p].l + tree[p].r) >> 1;
    if (r <= mid)
    {
        update(p << 1, l, r, val);
    }
    else if (l > mid)
    {
        update(p << 1 | 1, l, r, val);
    }
    else
    {
        update(p << 1, l, mid, val);
        update(p << 1 | 1, mid + 1, r, val);
    }
    tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
    tree[p].sumsum = tree[p << 1].sumsum + tree[p << 1 | 1].sumsum;
}

LL sumsum, sum;

void query(int p, int l, int r)
{
    if (l == tree[p].l && r == tree[p].r)
    {
        sum += tree[p].sum;
        sumsum += tree[p].sumsum;
        return;
    }
    int mid = (tree[p].l + tree[p].r) >> 1;
    pushdown(p);
    if (r <= mid)
    {
        query(p << 1, l, r);
    }
    else if (l > mid)
    {
        query(p << 1 | 1, l, r);
    }
    else
    {
        query(p << 1, l, mid);
        query(p << 1 | 1, mid + 1, r);
    }
}

int main()
{
    int n, m;
    while (~scanf("%d%d", &n, &m))
    {
        int op, x, y;
        LL val;
        build(1, 1, n);
        while (m--)
        {
            scanf("%d", &op);
            if (op == 1)
            {
                scanf("%d%d%lld", &x, &y, &val);
                ++x;
                ++y;
                update(1, x, y, val);
            }
            else
            {
                scanf("%d%d", &x, &y);
                ++x;
                ++y;
                sum = 0;
                sumsum = 0;
                query(1, x, y);
                double _x = sum * 1.0 / (y - x + 1);
                double ans = ((y - x + 1) * _x * _x - 2 * _x * sum + sumsum) * 1.0;
                ans /= (y - x + 1);
                cout << (LL)ans << endl;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值