codeforces 895E

(線段樹+2個lazy標記)
題意:先給定n(n<105) 個數字ai(ai<109) ,再給出q(q<105) 個操作,操作分兩種類型,1.將這些數字裏[l1,r1] 區間中任意一個數字和[l2,r2] 區間中任意一個數字交換。2.求[l,r] 區間所有數字的和(數學期望值)

思路:數組上的區間修改和查詢,想到用線段樹,這裏線段樹的每個結點維護三個值:數學期望總和,加法標記和乘法標記。爲什麼呢?假如題目給出一個操作1,那麼對於[l1,r1] 區間中的某個數字x而言,在操作1後,它的數學期望變成了xr1l1r1l1+1+i=r2i=l2air2l2+11r1l1+1 (左項爲該數字沒有被交換的期望,右項爲被交換的期望)。這裏要注意操作1時,[l1,r1] 裏的數學期望都是不一樣的,因爲乘法和除法針對的是這個區間裏每一個特定的數字,而不是整個區間(所以必須維護加法標記和乘法標記)

代碼:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r

using namespace std;
const int maxn = 100050;
const double eps = 1e-6;

double a[maxn], sum[maxn<<2];
double addv[maxn<<2], multv[maxn<<2];

int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    return (x < 0 ? -1:1);
}

void push_up(int p) {
    sum[p] = sum[p<<1] + sum[p<<1|1];
}

/** lazy tags are designed for the lower nodes. **/
void push_down(int p, int l, int r) {
    if(dcmp(multv[p])!=1 || dcmp(addv[p])!=0) {
        multv[p<<1] *= multv[p];
        multv[p<<1|1] *= multv[p];
        addv[p<<1] = multv[p]*addv[p<<1] + addv[p];
        addv[p<<1|1] = multv[p]*addv[p<<1|1] + addv[p];
        int mid = (l+r) >> 1;
        sum[p<<1] = multv[p]*sum[p<<1] + addv[p]*(mid-l+1);
        sum[p<<1|1] = multv[p]*sum[p<<1|1] + addv[p]*(r-mid);
        multv[p] = 1; addv[p] = 0;
    }
}

void build(int p, int l, int r) {
    multv[p] = 1; addv[p] = 0;
    if(l == r) {
        sum[p] = a[l];
        return ;
    }
    int mid = (l+r) >> 1;
    build(lson); build(rson);
    push_up(p);
}

/** y = k*x + b; **/
void modify(int p, int l, int r, int L, int R, double k, double b) {
    if(L <= l && r <= R) {
        sum[p] = k*sum[p] + b*(r-l+1);
        multv[p] *= k;
        addv[p] = k*addv[p] + b;
        return ;
    }
    push_down(p, l, r);
    int mid = (l+r) >> 1;
    if(L <= mid) modify(lson, L, R, k, b);
    if(R > mid) modify(rson, L, R, k, b);
    push_up(p);
}

double query(int p, int l, int r, int L, int R) {
    if(L <= l && r <= R)
        return sum[p];
    push_down(p, l, r);
    double ret = 0;
    int mid = (l+r) >> 1;
    if(L <= mid) ret += query(lson, L, R);
    if(R > mid) ret += query(rson, L, R);
    return ret;
}

int main() {
    //freopen("test.txt","r",stdin);
    int n, q;
    scanf("%d%d",&n,&q);
    for(int i=1; i<=n; i++)
        scanf("%lf",&a[i]);
    build(1, 1, n);
    while(q --) {
        int op, l1, r1, l2, r2;
        scanf("%d",&op);
        if(op == 1) {
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            double size1 = r1 - l1 + 1, size2 = r2 - l2 + 1;
            double t1 = query(1, 1, n, l1, r1), t2 = query(1, 1, n, l2, r2);
            //printf("query t1: %f t2:%f\n",t1,t2);
            modify(1, 1, n, l1, r1, (size1-1)/size1, t2/(size2*size1));
            modify(1, 1, n, l2, r2, (size2-1)/size2, t1/(size1*size2));
        }
        else {
            scanf("%d%d",&l1,&l2);
            double ans = query(1, 1, n, l1, l2);
            printf("%f\n",ans);
        }
    }
    return 0;
}
發佈了39 篇原創文章 · 獲贊 44 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章