Codeforces #448 Div2 E

#448 Div2 E

题意

给出一个数组,有两种类型操作:

  1. 选定不相交的两个区间,分别随机挑选一个数,交换位置。
  2. 查询区间和的期望。

分析

线段树区间更新区间求和。
既然是涉及到两个区间,那么对于第一个区间而言,它的和的期望由两部分组成:它剩下的数的和的期望,从第二个区间换过来的数的和的期望。第二个区间同理。
可以用两个数组分别(间接)维护这两部分的值(类似于线段树中常见的 lazy 数组)。

code

#include<bits/stdc++.h>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int N = 4e5 + 10;
double a[N], b[N], c[N];
void pushDown(int l, int r, int rt) {
    int m = l + r >> 1;
    b[rt << 1] *= b[rt];
    c[rt << 1] = c[rt << 1] * b[rt] + c[rt];
    a[rt << 1] = c[rt] * (m - l + 1) + a[rt << 1] * b[rt];
    b[rt << 1 | 1] *= b[rt];
    c[rt << 1 | 1] = c[rt << 1 | 1] * b[rt] + c[rt];
    a[rt << 1 | 1] = c[rt] * (r - m) + a[rt << 1 | 1] * b[rt];
    b[rt] = 1;
    c[rt] = 0;
}
void build(int l, int r, int rt) {
    b[rt] = 1;
    if(l == r) scanf("%lf", &a[rt]);
    else {
        int m = l + r >> 1;
        build(lson);
        build(rson);
        a[rt] = a[rt << 1] + a[rt << 1 | 1];
    }
}
void update(double bb, double cc, int L, int R, int l, int r, int rt) {
    if(l >= L && r <= R) {
        b[rt] *= bb;
        c[rt] = c[rt] * bb + cc;
        a[rt] = cc * (r - l + 1) + a[rt] * bb;
    } else {
        pushDown(l, r, rt);
        int m = l + r >> 1;
        if(L <= m) update(bb, cc, L, R, lson);
        if(R > m) update(bb, cc, L, R, rson);
        a[rt] = a[rt << 1] + a[rt << 1 | 1];
    }
}
double query(int L, int R, int l, int r, int rt) {
    if(l >= L && r <= R) return a[rt];
    else {
        pushDown(l, r, rt);
        int m = l + r >> 1;
        double res = 0;
        if(L <= m) res += query(L, R, lson);
        if(R > m) res += query(L, R, rson);
        return res;
    }
}
int main() {
    int n, q;
    cin >> n >> q;
    build(1, n, 1);
    while(q--) {
        int idx, w[4];
        cin >> idx;
        for(int i = 0; i < 6 - 2 * idx; i++) scanf("%d", &w[i]);
        if(idx == 1) {
            double c1 = query(w[2], w[3], 1, n, 1) / ((double)w[1] - w[0] + 1), c2 = query(w[0], w[1], 1, n, 1) / ((double)w[3] - w[2] + 1);
            update(((double)w[1] - w[0]) / ((double)w[1] - w[0] + 1), c1 / ((double)w[3] - w[2] + 1), w[0], w[1], 1, n, 1);
            update(((double)w[3] - w[2]) / ((double)w[3] - w[2] + 1), c2 / ((double)w[1] - w[0] + 1), w[2], w[3], 1, n, 1);
        } else {
            printf("%.8f
", query(w[0], w[1], 1, n, 1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/8005682.html