JZOJ Day 3-B组-T3——寻找神格

15 篇文章 0 订阅
1 篇文章 0 订阅

题目大意:

成为一个神后,最大的责任便是保护神界的人民,他们都出生在神界,但并不都具有神的实力。当然,神界人族的内部也有战争,他们一共分为N个部落,每两个部落之间都有可能发生战争。为了不然神界人族因为战争而损失惨重,神界的诸神将这些部落编号为1 ~ N,当这些部落的人数差距太大时,诸神便会降临,将一些部落的人带走,并放一些在别的部落中。而衡量所有部落人数差距的数值便是方差。接下来,Ta会告诉你一些部落的人数增加或减少的信息,并会不时的询问你编号为L~R的部落的总人数或是他们部落人数的方差。

解题思路:


数据范围是 n ≤ 100000 n\leq 100000 n100000所以我们可以用线段树(分块)分别维护区间平方和及区间和,然后回答即可。

A c c e p t e d   c o d e Accepted\ code Accepted code

#include<cstdio>

using namespace std;

struct node{
	long long l, r, sum, add, ft;
}tree[400001];
int n, q;
int a[100001];

void build(int p, int l, int r) {
	tree[p].l = l;
	tree[p].r = r;
	if (l == r) {
		tree[p].sum = a[l];
		tree[p].ft = a[l] * a[l];
		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].ft = tree[p<<1].ft + tree[p<<1|1].ft;
}

void spread(int p) {
	if (tree[p].add) {
		tree[p<<1].add += tree[p].add;
		tree[p<<1|1].add += tree[p].add;
		tree[p<<1].ft += 2 * tree[p<<1].sum * tree[p].add + (tree[p<<1].r - tree[p<<1].l + 1) * tree[p].add * tree[p].add;
		tree[p<<1|1].ft += 2 * tree[p<<1|1].sum * tree[p].add + (tree[p<<1|1].r - tree[p<<1|1].l + 1) * tree[p].add * tree[p].add;
		tree[p<<1].sum += tree[p].add * (tree[p<<1].r - tree[p<<1].l + 1);
		tree[p<<1|1].sum += tree[p].add * (tree[p<<1|1].r - tree[p<<1|1].l + 1);
		tree[p].add = 0;
	}
}

void change(int p, int l, int r, int v) {
	if (l <= tree[p].l && tree[p].r <= r) {
		tree[p].ft += (tree[p].sum * v << 1) + (tree[p].r - tree[p].l + 1) * v * v; 
		tree[p].sum += v * (tree[p].r - tree[p].l + 1);
		tree[p].add += v;
		return;
	}
	spread(p);
	int ft = (tree[p].l + tree[p].r) / 2;
	if (l <= ft) change(p<<1, l, r, v);
	if (r > ft) change(p<<1|1, l, r, v);
	tree[p].sum = tree[p<<1].sum + tree[p<<1|1].sum;
	tree[p].ft = tree[p<<1].ft + tree[p<<1|1].ft;
}

long long ask(int p, int l, int r) {
	if (l <= tree[p].l && tree[p].r <= r)
		return tree[p].sum;
	spread(p);
	int ft = (tree[p].l + tree[p].r) / 2;
	long long solve = 0;
	if (l <= ft) solve += ask(p<<1, l, r);
	if (r > ft) solve += ask(p<<1|1, l, r);
	return solve;
}

long long ask_(int p, int l, int r) {
	if (l <= tree[p].l && tree[p].r <= r)
		return tree[p].ft;
	spread(p);
	int ft = (tree[p].l + tree[p].r) >> 1;
	long long solve = 0;
	if (l <= ft) solve += ask_(p<<1, l, r);
	if (r > ft) solve += ask_(p<<1|1, l, r);
	return solve;
}

signed main() {
	scanf("%d %d", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	build(1, 1, n);
	int op = 0, x = 0, y = 0, z = 0;
	while (q--) {
		scanf("%d", &op);
		if (op == 0) {
			scanf("%d %d", &x, &y);
			change(1, x, x, y);
		} else if (op == 1) {
			scanf("%d %d %d", &x, &y, &z);
			change(1, x, y, z);
		} else if (op == 2) {
			scanf("%d %d", &x, &y);
			printf("%d\n", ask(1, x, y));
		} else if (op == 3) {
			scanf("%d %d", &x, &y);
			long long s1 = ask_(1, x, y), s2 = ask(1, x, y);
			double pjs = (double)s2 / (y - x + 1), s3 = s1 - 2 * s2 * pjs + (y - x + 1) * pjs * pjs;
			printf("%.10lf\n", s3 / (y - x + 1));
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值