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
inputCopy
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
inputCopy
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
inputCopy
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

题意

A和B在玩一个游戏。现在A记住一个序列,然后闭上眼睛,B每次有两种操作(开始干坏事了)
- 第一种操作
取两不相交区间(l1,r1)(l2,r2),B在两区间中各随意取一个数,然后交换位置。
- 第二种操作
询问A区间(l,r)中元素和的期望值

题解

考虑到是期望值,便想到期望的可加性。结合区间更新区间询问,就有一个线段树的大致想法。于是着手解决期望的求法,在第一种操作时设第一个区间的长度为 num n u m ,第二个区间为 cnt c n t 。对于第一个区间的一个数字 a a ,保持为a的概率是num1num,选到它的概率是 1num 1 n u m ,在选到条件下转变为第二个区间的某个数 bi b i 的概率为 1cnt 1 c n t 。而期望等于概率乘以权值的和,即当前位的期望可以写成

num1numa+cnti=1(1numcntbi) n u m − 1 n u m ∗ a + ∑ i = 1 c n t ( 1 n u m ∗ c n t ∗ b i )

从而发现可以在线段树内维护区间和sum,用lazy1和lazy2标记分别标记 num1num n u m − 1 n u m cnti=1(1numcntbi) ∑ i = 1 c n t ( 1 n u m ∗ c n t ∗ b i ) 。区间更新区间询问即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <vector>
#include <cstring>
#include <complex>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn =1e5+7;
const double pi = acos(-1.0);
const int v2 = (mod+1)/2;
int n,q,a[maxn];
struct {
    int l,r;
    double sum,k,lazy;
}b[4*maxn];

void push_up(int now)
{
    b[now].sum = b[now<<1].sum+b[now<<1|1].sum;
}
void push_down(int now)
{
    double sum = b[now].sum,k = b[now].k,lazy = b[now].lazy;
    if(lazy!=0||k!=1)
    {
        b[now].k = 1;
        b[now].lazy = 0;
        b[now<<1].k*=k;
        b[now<<1].lazy = b[now<<1].lazy*k+lazy;
        int l = b[now<<1].l,r = b[now<<1].r;
        b[now<<1].sum = b[now<<1].sum*k+(r-l+1)*lazy;

        b[now<<1|1].k*=k;
        b[now<<1|1].lazy = b[now<<1|1].lazy*k+lazy;
        l = b[now<<1|1].l,r = b[now<<1|1].r;
        b[now<<1|1].sum = b[now<<1|1].sum*k+(r-l+1)*lazy;
    }
}

void build(int now,int l,int r)
{
    b[now].l = l,b[now].r = r;
    b[now].k = 1,b[now].lazy = 0;
    if(l==r)
    {
        b[now].sum = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    push_up(now);
}
void update(int now,int l,int r,double k,double lazy)
{
    int L = b[now].l,R = b[now].r;
    if(l<=L&&R<=r)
    {
        b[now].sum = b[now].sum*k+(R-L+1)*lazy;
        b[now].k*=k;
        b[now].lazy = b[now].lazy*k+lazy;
        return;
    }
    int mid = (L+R)>>1;
    push_down(now);
    if(mid>=l)update(now<<1,l,min(r,mid),k,lazy);
    if(mid<r)update(now<<1|1,max(l,mid+1),r,k,lazy);
    push_up(now);
}

double query(int now,int l,int r)
{
    int L = b[now].l,R = b[now].r;
    if(l<=L&&R<=r)
    {
        return b[now].sum;
    }
    double res = 0;
    int mid = (L+R)>>1;
    push_down(now);
    if(mid>=l) res+=query(now<<1,l,min(r,mid));
    if(mid<r) res+=query(now<<1|1,max(l,mid+1),r);
    return res;
}
int main()
{
    scanf("%d %d",&n,&q);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    for(int i = 0;i < q;i++)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int l1,r1,l2,r2;
            scanf("%d %d %d %d",&l1,&r1,&l2,&r2);
            int num = r1-l1+1,cnt = r2-l2+1;
            double sum2 = query(1,l2,r2),sum1 = query(1,l1,r1);
            double k = 1.0*(num-1)/num,c = 1.0/num/cnt*sum2;
            update(1,l1,r1,k,c);
            k = 1.0*(cnt-1)/cnt,c = 1.0/cnt/num*sum1;
            update(1,l2,r2,k,c);
        }
        else
        {
            int l1,r1;
            scanf("%d %d",&l1,&r1);
            printf("%f\n",query(1,l1,r1));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值