码迷,mamicode.com
首页 > 其他好文 > 详细

[CF895E] Eyes Closed(线段树,期望)

时间:2019-09-12 13:40:29      阅读:92      评论:0      收藏:0      [点我收藏+]

标签:线性   name   根据   desc   rac   root   query   etc   ble   

Desctiption

传送门:Portal

大致题意: 给你一个序列, 支持两种操作:

  1. 1 l1 r1 l2 y2\([l1, r1]\)随机选择一个数a, \([l2, r2]\) 内随机选择一个数b, 交换a, b.
  2. 2 l r 询问一个区间的期望.

\[ n \leq 200000; a_i \leq 1e9 \]

Solution

根据==期望线性性==,只需要维护出==每个位置元素值的期望==就可以.

==区间操作期望==问题的经典套路是==维护出每个位置的期望==.

考虑一个数字\(a_i\)

他有\(\frac{len - 1}{len}\) 的概率保持原数, 否则,根据全期望公式, 它会变成\(E(b_i) = \sum\frac{b_i}{lenB}\)

那么有:
\[ A_i = \frac{(lenA - 1)A_i + \sum \frac{b_i}{lenB}}{lenA} \]
\(b_i\)也同理.

所以我们只需要维护一个区间加/乘, 区间求和的线段树就可以了.

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
int read() {
    char ch = getchar();
    int x = 0, flag = 1;
    for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;
}
void write(int x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + 48);
}

const int Maxn = 200009;
int a[Maxn];

namespace SGMTtree {
    double tree[Maxn << 3], addTag[Maxn << 3], mulTag[Maxn << 3];
#define lc(x) ((x) << 1)
#define rc(x) (((x) << 1) | 1)
#define ls rt << 1, l, mid
#define rs (rt << 1) | 1, mid + 1, r
    void setAdd(int root, int l, int r, double v) {
        tree[root] += v * (r - l + 1.0); addTag[root] += v;
    }
    void setMul(int root, int l, int r, double v) {
        tree[root] *= v;
        mulTag[root] *= v; addTag[root] *= v;
    }
    void (*setTag)(int, int, int, double);
    void set(int p) {
        if(p == 1) setTag = setAdd;
        if(p == 2) setTag = setMul;
    }

    void pushdown(int rt, int l, int r) {
        int mid = (l + r) >> 1;
        if (mulTag[rt] != 1.0) {
            setMul(ls, mulTag[rt]), setMul(rs, mulTag[rt]);
            mulTag[rt] = 1;
        }
        if (addTag[rt] != 0.0) {
            setAdd(ls, addTag[rt]); setAdd(rs, addTag[rt]); 
            addTag[rt] = 0;
        }
    }
    void pushup(int rt) { tree[rt] = tree[lc(rt)] + tree[rc(rt)]; }

    void build(int rt, int l, int r) {
        addTag[rt] = 0, mulTag[rt] = 1;
        if (l == r) {
            tree[rt] = a[l];
            return ;
        }
        int mid = (l + r) >> 1;
        build(ls), build(rs);
        pushup(rt);
    }
    void modify(int rt, int l, int r, int p, int q, double v) {
        if (p > q) return ;
        if (p <= l && r <= q) {
            setTag(rt, l, r, v);
            return ;
        }
        int mid = (l + r) >> 1; pushdown(rt, l, r);
        if (q <= mid) modify(ls, p, q, v);
        else if (p > mid) modify(rs, p, q, v);
        else modify(ls, p, q, v), modify(rs, p, q, v);
        pushup(rt);
    }
    double query(int rt, int l, int r, int p, int q) {
        if (p <= l && r <= q) return tree[rt];
        int mid = (l + r) >> 1; pushdown(rt, l, r);
        if (q <= mid) return query(ls, p, q);
        else if (p > mid) return query(rs, p, q);
        else return query(ls, p, q) + query(rs, p, q);
    }
#undef lc
#undef rc
#undef ls
#undef rs
};

int n, q;

void init() {
    n = read(); q = read();
    rep (i, 1, n) a[i] = read();
    SGMTtree :: build(1, 1, n);
}

void solve() {
    rep (i, 1, q) {
        int opt = read();
        if (opt == 1) {
            int l1 = read(), r1 = read(), l2 = read(), r2 = read();
            double c = r1 - l1 + 1.0, d = r2 - l2 + 1.0, tmp1 = SGMTtree :: query(1, 1, n, l1, r1), tmp2 = SGMTtree :: query(1, 1, n, l2, r2);
            SGMTtree :: set(2), SGMTtree :: modify(1, 1, n, l1, r1, c - 1.0);
            SGMTtree :: set(2), SGMTtree :: modify(1, 1, n, l2, r2, d - 1.0);
            SGMTtree :: set(1), SGMTtree :: modify(1, 1, n, l1, r1, tmp2 / d);
            SGMTtree :: set(1), SGMTtree :: modify(1, 1, n, l2, r2, tmp1 / c);
            SGMTtree :: set(2), SGMTtree :: modify(1, 1, n, l1, r1, 1 / c);
            SGMTtree :: set(2), SGMTtree :: modify(1, 1, n, l2, r2, 1 / d);
        }
        if (opt == 2) {
            int l = read(), r = read();
            printf("%.7lf\n", SGMTtree :: query(1, 1, n, l, r));
        }
    }
}

int main() {
//  freopen("CF895E.in", "r", stdin);
//  freopen("CF895E.out", "w", stdout);

    init();
    solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;
}

调试:

线段树函数指针必须要用namespace.

[CF895E] Eyes Closed(线段树,期望)

标签:线性   name   根据   desc   rac   root   query   etc   ble   

原文地址:https://www.cnblogs.com/qrsikno/p/11511080.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!