rt,样例都是错的...求调
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 5;
struct node{
double sum, pw, tag;//pw为区间平方和
node() {
sum = pw = tag = 0;
}
} tr[N];
int n, m, a[N];
void pushup(node &u, node &l, node &r) {
u.sum = l.sum + r.sum;
u.pw = l.pw + r.pw;
}
void pushup(int u) {
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void build(int x, int l, int r) {
if (l == r) {
tr[l].sum = a[l], tr[l].pw = a[l] * a[l];
return ;
}
int mid = l + r >> 1;
build(l << 1, l, mid), build(l << 1 | 1, mid + 1, r);
pushup(x);
}
void pushdown(int x, int l, int r) {
int ls = x << 1, rs = ls | 1, mid = l + r >> 1;
//标记下放左孩子
tr[ls].pw = tr[ls].pw + tr[x].tag * tr[ls].sum + (mid - l + 1) * tr[x].tag * tr[x].tag;
tr[ls].sum = tr[ls].sum + tr[x].tag * (mid - l + 1), tr[ls].tag += tr[x].tag;
//标记下放右孩子
tr[rs].pw = tr[rs].pw + tr[x].tag * tr[rs].sum + (r - mid) * tr[x].tag * tr[x].tag;
tr[rs].sum = tr[rs].sum + tr[x].tag * (r - mid), tr[rs].tag += tr[x].tag;
//标记下放完了,清零
tr[x].tag = 0;
}
void modify(int x, int l, int r, int ll, int rr, double k) {//给区间[ll,rr]加上k
if (l == ll && r == rr) {//找到修改区间了
tr[x].pw = tr[x].pw + 2 * k * tr[x].sum + k * k * (r - l + 1);
tr[x].sum = tr[x].sum + k * (r - l + 1), tr[x].tag += k;
return ;
}
int mid = l + r >> 1;
if (tr[x].tag != 0)
pushdown(x, l, r);
if (ll > mid)//要修改的区间全在右孩子上
modify(x << 1 | 1, mid + 1, r, ll, rr, k);
else if (rr <= mid)//要修改的区间全在左孩子上
modify(x << 1, l, mid, ll, rr, k);
else//修改区间横跨左右孩子
modify(x << 1, l, mid, ll, mid, k), modify(x << 1 | 1, mid + 1, r, mid + 1, rr, k);
pushup(x);//算完孩子,更新自己
}
double query1(int x, int l, int r, int ll, int rr) {//返回[ll, rr]区间和
if (l == ll && r == rr)
return tr[x].sum;
int mid = l + r >> 1;
if (tr[x].tag != 0)
pushdown(x, l, r);
if (ll > mid)//答案在右孩子
return query1(x << 1 | 1, mid + 1, r, ll, rr);
else if (rr <= mid)//答案在左孩子
return query1(x << 1, l, mid, ll, rr);
else//答案横跨左右孩子
return (query1(x << 1, l, mid, ll, mid) + query1(x << 1 | 1, mid + 1, r, mid + 1, rr));
}
double query2(int x, int l, int r, int ll, int rr) {//返回[ll, rr]区间平方和
if (l == ll && r == rr)
return tr[x].pw;
int mid = l + r >> 1;
if (tr[x].tag != 0)
pushdown(x, l, r);
if (ll > mid)//答案在右孩子
return query2(x << 1 | 1, mid + 1, r, ll, rr);
else if (rr <= mid)//答案在左孩子
return query2(x << 1, l, mid, ll, rr);
else//答案横跨左右孩子
return (query2(x << 1, l, mid, ll, mid) + query2(x << 1 | 1, mid + 1, r, mid + 1, rr));
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i)
cin >> a[i];
build(1, 1, n);
while (m --) {
int op, x, y; double k;
cin >> op;
if (op == 1) {
cin >> x >> y >> k;
modify(1, 1, n, x, y, k);
}
if (op == 2) {
cin >> x >> y;
printf("%.4lf\n", 1.0 * query1(1, 1, n, x, y) / (y - x + 1));
}
if (op == 3) {
cin >> x >> y;
double ans1 = query1(1, 1, n, x, y) * 1.0 / (y - x + 1), ans2 = query2(1, 1, n, x, y);
printf("%.4lf\n", ans2 * 1.0 / (y - x + 1) - 1.0 * ans1 * ans1);
}
}
return 0;
}