codeforces 895E

来源:互联网 发布:2016免费洗车软件 编辑:程序博客网 时间:2024/06/05 14:27

(线段树+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,rusing 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;}
原创粉丝点击