您的位置:首页 > 其它

codeforces 895E Eyes Closed 线段树 期望 数学

2017-11-27 16:34 627 查看
简略题意:

两种操作。

1. [l1, r1]之间随机一个数,[l2, r2]之间随机一个数,把两个交换

2. 问[l, r]区间和的数学期望是多少。

先考虑左部分区间,假设其总和为sum1, 长度为len1, 右部分区间总和为sum2,长度为len2。

那么对于左区间随机一个数x,进行操作后的数学期望值为:

len1−1len1∗x+1len1∗sum2len2。

可以发现这其实是对x进行了线性变换y = kx + b,且这种变换对于左边整个区间而言都是相同的。

同理可得右区间的变换为:

len2−1len2∗x+1len1∗sum1len1。

因此我们只需要维护区间乘法,区间加法,区间求和的线段树即可。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
int dcmp(double x) { if(fabs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;
/*
题意:
两种操作。
1. [l1, r1]之间随即一个数,[l2, r2]之间随机一个数,把两个交换
2. 问[l, r]区间和的数学期望是多少。
*/
namespace solver {
int n, q;
const int maxn = 110000;
struct A {
double sum, mul, add;
} tr[maxn<<2];
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
void pushup(int rt) {
tr[rt].sum = tr[rt<<1].sum + tr[rt<<1|1].sum;
}
void build(int l, int r, int rt) {
tr[rt].sum = tr[rt].add = 0;
tr[rt].mul = 1;
if(l == r) {
scanf("%lf", &tr[rt].sum);
return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(rt);
}
void pushdown(int l, int r, int rt) {
int m = l + r >> 1;
tr[rt<<1].sum = tr[rt].mul * tr[rt<<1].sum + (m - l + 1) * tr[rt].add;
tr[rt<<1].mul *= tr[rt].mul;
tr[rt<<1].add = tr[rt].mul * tr[rt<<1].add + tr[rt].add;
tr[rt<<1|1].sum = tr[rt].mul * tr[rt<<1|1].sum + (r - m) * tr[rt].add;
tr[rt<<1|1].mul *= tr[rt].mul;
tr[rt<<1|1].add = tr[rt].mul * tr[rt<<1|1].add + tr[rt].add;
tr[rt].add = 0;
tr[rt].mul = 1;
}
void update_mul(int L, int R, double v, int l, int r, int rt) {
if(L <= l && R >= r) {
tr[rt].sum *= v;
tr[rt].mul *= v;
tr[rt].add *= v;
return ;
}
pushdown(l, r, rt);
int m = l + r >> 1;
if(L <= m) update_mul(L, R, v, lson);
if(R > m) update_mul(L, R, v, rson);
pushup(rt);
}
void update_add(int L, int R, double v, int l, int r, int rt) {
if(L <= l && R >= r) {
tr[rt].sum += (r - l + 1) * v;
tr[rt].add += v;
return ;
}
pushdown(l, r, rt);
int m = l + r >> 1;
if(L <= m) update_add(L, R, v, lson);
if(R > m) update_add(L, R, v, rson);
pushup(rt);
}
double ask(int L, int R, int l, int r, int rt) {
if(L <= l && R >= r) {
return tr[rt].sum;
}
int m = l + r >> 1;
double ans = 0;
pushdown(l, r, rt);
if(L <= m) ans += ask(L, R, lson);
if(R > m) ans += ask(L, R, rson);
pushup(rt);
return ans;
}
void solve() {
scanf("%d%d", &n, &q);
build(1, n, 1);
for(int i = 1; i <= q; i++) {
int id; scanf("%d", &id);
if(id == 1) {
int l1, r1, l2, r2; scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
double sum1 = ask(l1, r1, 1, n, 1), sum2 = ask(l2, r2, 1, n, 1);
double len1 = r1 - l1 + 1, len2 = r2 - l2 + 1;
update_mul(l1, r1, (len1-1)/len1, 1, n, 1);
update_mul(l2, r2, (len2-1)/len2, 1, n, 1);
update_add(l1, r1, 1.0/len1 * (sum2/len2), 1, n, 1);
update_add(l2, r2, 1.0/len2 * (sum1/len1), 1, n, 1);
} else {
int l, r; scanf("%d%d", &l, &r);
printf("%.7f\n", ask(l, r, 1, n, 1));
}
}
};
}

int main() {
#ifdef file
freopen("gangsters.in", "r", stdin);
freopen("gangsters.out", "w", stdout);
#endif // file
solver::solve();
return 0;
}

/*
5 5
1 2 3 4 5

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: