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;
}
发布了40 篇原创文章 · 获赞 44 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/Site1997/article/details/78701117