Codeforces Round #448 (Div. 2) E. Eyes Closed

E. Eyes Closed
time limit per test2.5 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Vasya and Petya were tired of studying so they decided to play a game. Before the game begins Vasya looks at array a consisting of n integers. As soon as he remembers all elements of a the game begins. Vasya closes his eyes and Petya does q actions of one of two types:

1) Petya says 4 integers l1, r1, l2, r2 — boundaries of two non-intersecting segments. After that he swaps one random element from the [l1, r1] segment with another random element from the [l2, r2] segment.

2) Petya asks Vasya the sum of the elements of a in the [l, r] segment.

Vasya is a mathematician so he answers Petya the mathematical expectation of the sum of the elements in the segment.

Your task is to write a program which will answer the second type questions as Vasya would do it. In other words your program should print the mathematical expectation of the sum of the elements of a in the [l, r] segment for every second type query.

Input
The first line contains two integers n, q (2 ≤ n ≤ 105, 1 ≤ q ≤ 105) — the number of elements in the array and the number of queries you need to handle.

The second line contains n integers ai (1 ≤ ai ≤ 109) — elements of the array.

The next q lines contain Petya’s actions of type 1 or 2.

If it is a type 1 action then the line contains 5 integers 1, l1, r1, l2, r2 (1 ≤ l1 ≤ r1 ≤ n, 1 ≤ l2 ≤ r2 ≤ n).

If it is a type 2 query then the line contains 3 integers 2, l, r (1 ≤ l ≤ r ≤ n).

It is guaranteed that there is at least one type 2 query and segments [l1, r1], [l2, r2] don’t have common elements.

Output
For each type 2 query print one real number — the mathematical expectation of the sum of elements in the segment.

Your answer will be considered correct if its absolute or relative error doesn’t exceed 10 - 4 — formally, the answer is correct if where x is jury’s answer and y is yours.

Examples
input
4 4
1 1 2 2
1 2 2 3 3
2 1 2
1 1 2 3 4
2 1 2
output
3.0000000
3.0000000
input
10 5
1 1 1 1 1 2 2 2 2 2
1 1 5 6 10
2 1 5
1 1 5 6 10
1 1 5 6 10
2 6 10
output
6.0000000
8.0400000
input
10 10
1 2 3 4 5 6 7 8 9 10
1 1 5 6 10
1 1 5 6 10
2 1 5
1 1 3 6 9
2 1 3
1 5 7 8 10
1 1 1 10 10
2 1 5
2 7 10
2 1 10
output
23.0000000
14.0000000
28.0133333
21.5733333
55.0000000

题意:给出n个数,然后有两种操作,1:将l到r之间的任意一个数和l2,r2之间的任意一个数交换位置,2:输出当前l,r之间的和的期望。
做法:算出每个数的期望,然后所有操作的都在当前的期望上进行就好了。线段树区间更新。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
double sum[N<<2],lazy[N<<2],lazy2[N<<2];
int n,m;
void pushdown(int l,int r,int rt){
    lazy[rt<<1] *= lazy[rt];
    lazy2[rt<<1] *= lazy[rt];
    lazy2[rt<<1] += lazy2[rt];
    lazy[rt<<1|1] *= lazy[rt];
    lazy2[rt<<1|1] *= lazy[rt];
    lazy2[rt<<1|1] += lazy2[rt];
    sum[rt<<1] *= lazy[rt];
    sum[rt<<1] += lazy2[rt]*l;
    sum[rt<<1|1] *= lazy[rt];
    sum[rt<<1|1] += lazy2[rt]*r;
    lazy[rt] = 1;
    lazy2[rt] = 0;
}

void pushup(int rt){
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}

void build(int l,int r,int rt){
    lazy[rt] = 1.0;
    lazy2[rt] = 0;
    if(l == r){
        scanf("%lf",&sum[rt]);
        return ;
    }
    int mid = l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}

double query(int L,int R,int l,int r,int rt){
    if(L <= l &&R >= r){
        return sum[rt];
    }
    double ret = 0;
    int mid = r+l>>1;
    pushdown(mid-l+1,r-mid,rt);
    if(mid >= L) ret += query(L,R,l,mid,rt<<1);
    if(mid < R) ret += query(L,R,mid+1,r,rt<<1|1);
    pushup(rt);
    return ret;
}

void update(int L,int R,double x,double y,int l,int r,int rt){
    if(L <= l && R >= r){
        lazy[rt] *= x;
        lazy2[rt] *= x;
        lazy2[rt] += y;
        sum[rt] = sum[rt]*x+y*(r-l+1);
        return ;
    }
    int mid = r+l>>1;
    pushdown(l-mid+1,r-mid,rt);
    if(mid >= L) update(L,R,x,y,l,mid,rt<<1);
    if(mid < R) update(L,R,x,y,mid+1,r,rt<<1|1);
    pushup(rt);
}

int main(){
    cin >>n >> m;
    build(1,n,1);
    for(int i = 1;i <= m;i ++){
        int op,l,r,l2,r2;
        scanf("%d",&op);
        if(op == 1){
            scanf("%d %d %d %d",&l,&r,&l2,&r2);
            double sum1 = query(l,r,1,n,1);
            double sum2 = query(l2,r2,1,n,1);
            int x = (r-l+1),y = (r2-l2+1);
            update(l,r,(x-1)*1.0/x,sum2/x/y,1,n,1);
            update(l2,r2,(y-1)*1.0/y,sum1/x/y,1,n,1);
        }
        else{
            scanf("%d %d",&l,&r);
            printf("%lf\n",query(l,r,1,n,1));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值