【BZOJ 4821】【SDOI 2017】相关分析

把公式化开来得到:
a=ri=l(xiyix¯yixiy¯+x¯y¯)ri=l(x2i2x¯xi+x¯2)
把分子的第二项拿出来结合ri=l就可以得到x¯ri=lyi=x¯y¯(rl+1),第三项同理,分母同理,再合并一下就可以得到:
a=xiyix¯y¯(rl+1)ri=lx2ix¯2(rl+1)
然后用线段树维护一下xyxyx2即可。

2号询问就是个简单的区间加,注意到:
(x+Δx)(y+Δy)
=(xy+Δxy+Δyx+ΔxΔy)
=xy+yΔx+xΔy+ΔxΔy,就可以维护了。
3号询问可以看做是先将第i号元素变为i然后执行一次2号操作。用一下平方和公式即可。
注意:当执行3号操作的覆盖操作时要将所有2号操作的lazy-tag清除掉。

#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
#define mod 1000000007
#define ls x<<1
#define rs x<<1|1
#define N 100005
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct TREE{double sumx,sumy,sumxy,sumxx,tag_x,tag_y; int l,r,len,tag_c;} tree[N*4];
double xx[N],yy[N];
int n,m,i,opt,l,r,dx,dy;
void pushup(int x)
{
    tree[x].sumx = tree[ls].sumx + tree[rs].sumx;
    tree[x].sumy = tree[ls].sumy + tree[rs].sumy;
    tree[x].sumxy = tree[ls].sumxy + tree[rs].sumxy;
    tree[x].sumxx = tree[ls].sumxx + tree[rs].sumxx;
}
void build(int x,int l,int r)
{
    tree[x].len = r - l + 1; tree[x].l = l; tree[x].r = r;
    if (l == r) 
        {
            tree[x].sumx = xx[l]; tree[x].sumy = yy[l];
            tree[x].sumxy = xx[l] * yy[l]; 
            tree[x].sumxx = xx[l] * xx[l];
            return;
        }
    int mid = (l + r) >> 1;
    build(ls,l,mid); build(rs,mid+1,r); pushup(x);
    }
double calc(int x) {return (double)x*(x+1)*(2*x+1)/6;}
void update_a(int x,double dx,double dy)
{
    tree[x].sumxy += tree[x].sumx * dy + tree[x].sumy * dx + tree[x].len * dx * dy;
    tree[x].sumxx += tree[x].sumx * dx * 2 + tree[x].len * dx * dx;
    tree[x].sumx += dx * tree[x].len;
    tree[x].sumy += dy * tree[x].len;
    tree[x].tag_x += dx; tree[x].tag_y += dy;
}
void update_c(int x)
{
    tree[x].sumx = tree[x].sumy = (double)(tree[x].l+tree[x].r)*tree[x].len/2;
    tree[x].sumxy = tree[x].sumxx = calc(tree[x].r) - calc(tree[x].l-1);
    tree[x].tag_c = 1;
    tree[x].tag_x = tree[x].tag_y = 0;
}
void pushdown(int x)
{
    if (tree[x].tag_c) {update_c(ls); update_c(rs); tree[x].tag_c = 0;}
    if (tree[x].tag_x || tree[x].tag_y)
        {
            update_a(ls,tree[x].tag_x,tree[x].tag_y);
            update_a(rs,tree[x].tag_x,tree[x].tag_y);
            tree[x].tag_x = tree[x].tag_y = 0;
        }
}
void add(int x,int l,int r,int L,int R,int dx,int dy)
{
    if (L <= l && r <= R) {update_a(x,dx,dy); return;}
    pushdown(x);
    int mid = (l + r) >> 1;
    if (L <= mid) add(ls,l,mid,L,R,dx,dy);
    if (mid < R) add(rs,mid+1,r,L,R,dx,dy);
    pushup(x);
}
void change(int x,int l,int r,int L,int R)
{
    if (L <= l && r <= R) {update_c(x); return;}
    pushdown(x);
    int mid = (l + r) >> 1;
    if (L <= mid) change(ls,l,mid,L,R);
    if (mid < R) change(rs,mid+1,r,L,R);
    pushup(x);
}
double query(int x,int l,int r,int L,int R,int opt)
{
    if (L <= l && r <= R) 
        {
            if (opt == 1) return tree[x].sumx;
            if (opt == 2) return tree[x].sumy;
            if (opt == 3) return tree[x].sumxy;
            if (opt == 4) return tree[x].sumxx;
        }
    pushdown(x);
    int mid = (l + r) >> 1; double res = 0;
    if (L <= mid) res += query(ls,l,mid,L,R,opt);
    if (mid < R) res += query(rs,mid+1,r,L,R,opt);
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    fo(i,1,n) scanf("%lf",&xx[i]);
    fo(i,1,n) scanf("%lf",&yy[i]);
    build(1,1,n);
    while (m--)
        {
            scanf("%d",&opt);
            scanf("%d%d",&l,&r);
            if (opt == 1)
                {
                    double res1 = query(1,1,n,l,r,1); double res2 = query(1,1,n,l,r,2);
                    double res3 = query(1,1,n,l,r,3); double res4 = query(1,1,n,l,r,4);
                    double p = res3 - res1 * res2 / (r-l+1);
                    double q = res4 - res1 * res1 / (r-l+1);
                    printf("%.10lf\n",p/q);
                }   else
                {
                    scanf("%d%d",&dx,&dy);
                    if (opt == 3) change(1,1,n,l,r);
                    add(1,1,n,l,r,dx,dy);
                }       
        }
    return 0;   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值