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

来源:互联网 发布:office mac 汉化补丁 编辑:程序博客网 时间:2024/06/13 02:23

简略题意:
两种操作。
1. [l1, r1]之间随机一个数,[l2, r2]之间随机一个数,把两个交换
2. 问[l, r]区间和的数学期望是多少。

先考虑左部分区间,假设其总和为sum1, 长度为len1, 右部分区间总和为sum2,长度为len2
那么对于左区间随机一个数x,进行操作后的数学期望值为:
len11len1x+1len1sum2len2
可以发现这其实是对x进行了线性变换y = kx + b,且这种变换对于左边整个区间而言都是相同的。
同理可得右区间的变换为:
len21len2x+1len1sum1len1

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

#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 51 2 3 4 5*/