题目大意

给定n个元素的数列,每一个元素有x和y两种元素,现在有三种操作:

\(1\ L\ R\)

设\(xx\)为\([l,r]\)的元素的\(x_i\)的平均值,\(yy\)同理



求 \(\frac{\sum_{i=L}^R(x_i-xx)(y_i-yy)} {\sum_{i=L}^R(xi-xx)^2}\)

$2\ L\ R\ S\ T\ \(
将\)[L,R]\(中的每个元素的\)x_i\(+S,\)y_i$+T

$3\ L\ R\ S\ T\ \(
对于\)[L,R]\(中的每个元素,设其为\)i\(,将它的\)x_i\(改为\)S+i\(,\)y_i\(改为\)T+i$

其中\(n \le 100000 , m\le100000\)



要是回答1询问的话,首先需要将线段树维护一个每个元素的x的平方的和、x的和、y的和,以及每一个元素x*y的和

那么我们就开一个struct来记录这些值

struct Node{
double sx,sy,sqr,xy,sum;
};

up数组的话,和普通的线段树差不多

void up(int root)
{
f[root].sx=f[2*root].sx+f[2*root+1].sx;
f[root].sy=f[2*root].sy+f[2*root+1].sy;
f[root].sqr=f[2*root].sqr+f[2*root+1].sqr;
f[root].xy=f[2*root].xy+f[2*root+1].xy;
}

对于pushdown,我们首先考虑增加操作,对于一个区间\([l,r]\)

\(\sum (x_i+S)\) = \(\sum x_i +(r-l+1)\times S\)

\(\sum (y_i+T)\) = \(\sum y_i +(r-l+1)\times T\)

\(\sum(x_i+S)^2\) = \(\sum x_i^2 + 2\times \sum x_i \times S +S^2\)

\(\sum(x_I+S)(y_i+T)\) = \(\sum x_i y_i\) + \(T\times \sum x_i\)+\(S\times \sum y_i\)+\((r-l+1)\times T \times S\)

经过一波操作,就可以直接在原来的基础上进行加法的操作了

注意!!! 先更新乘法那些,再更新加法

if (add[root].x || add[root].y)
{
add[2*root].x+=add[root].x;
add[2*root+1].x+=add[root].x;
add[2*root].y+=add[root].y;
add[2*root+1].y+=add[root].y;
f[2*root].sqr+=(mid-l+1)*add[root].x*add[root].x+2*f[2*root].sx*add[root].x;
f[2*root+1].sqr+=(r-mid)*add[root].x*add[root].x+2*f[2*root+1].sx*add[root].x;
f[2*root].xy+=(mid-l+1)*add[root].x*add[root].y+f[2*root].sx*add[root].y+f[2*root].sy*add[root].x;
f[2*root+1].xy+=(r-mid)*add[root].x*add[root].y+f[2*root+1].sx*add[root].y+f[2*root+1].sy*add[root].x;
f[2*root].sx+=(mid-l+1)*add[root].x;
f[2*root+1].sx+=(r-mid)*add[root].x;
f[2*root].sy+=(mid-l+1)*add[root].y;
f[2*root+1].sy+=(r-mid)*add[root].y;
add[root].x=0;
add[root].y=0;
}

那么那么那么,对于有覆盖操作的的呢?

我们可以这么想,把覆盖分解成两步

1.把\(x_i\)和\(y_i\)修改成\(i\)

2.将\(x_i+S\),\(y_i+T\)

那么我们思考,全部覆盖成\(i\)应该怎么做呢QwQ

首先,一旦一个区间被打了覆盖标记,那么之前的add 的标记就需要全部清空

我们会发现修改完的序列是这样的\(1,2,3,4,5.....\)

而\(\sum_{i=1}^n i^2 = \frac {n(n+1)(2n+1)}{6}\)

所以,对于一个区间\([l,r]\)

\(\sum x_i = \sum y_i = \frac{(r-l+1)(r+l)}{2}\)



\(\sum x_i^2 = \sum x_i y_i = \frac {(r+1)r(2r+1)}{6} - \frac{l(l-1)(2l-1)}{6}\)

在下传标记的时候,当把覆盖标记下传完之后,把传到的那两个子区间 的 \(add\) 清空

一定记得把add的标记清空!!!!!!

if (flag[root])
{
flag[2*root+1]=1;flag[2*root]=1;flag[root]=0;add[2*root].x=add[2*root].y=add[2*root+1].x=add[2*root+1].y=0;
f[2*root].sx=(l+mid)*(mid-l+1)/2;
f[2*root].sy=(l+mid)*(mid-l+1)/2;
f[2*root+1].sx=(r+mid+1)*(r-mid-1+1)/2;
f[2*root+1].sy=(r+mid+1)*(r-mid-1+1)/2;
f[2*root].xy=f[2*root].sqr=(mid+1)*mid*(2*mid+1)/6-(l-1)*l*(2*l-1)/6;
f[2*root+1].xy=f[2*root+1].sqr=(r+1)*r*(2*r+1)/6-(mid)*(mid+1)*(2*mid+1)/6;
}

build也和普通的线段树没什么区别

void build(int root,int l,int r)
{
if (l==r)
{
f[root].sx=a[l].x;
f[root].sy=a[l].y;
f[root].xy=a[l].x*a[l].y;
f[root].sqr=a[l].x*a[l].x;
return;
}
int mid = (l+r) >> 1;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
up(root);
}

再就是update和change了 QwQ我的做法是把区间加和区间赋值分开写,其实和pushdown的操作基本上完全一样

直接上代码了

void update(int root,int l,int r,int x,int y,double px,double py)
{
if (x<=l && r<=y)
{
add[root].x+=px;
add[root].y+=py;
f[root].xy+=(double)(r-l+1)*px*py+(double)f[root].sx*py+(double)f[root].sy*px;
f[root].sqr+=(double)(r-l+1)*px*px+(double)f[root].sx*px*2;
f[root].sx+=(double)(r-l+1)*px;
f[root].sy+=(double)(r-l+1)*py;
return;
}
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) update(2*root,l,mid,x,y,px,py);
if (y>mid) update(2*root+1,mid+1,r,x,y,px,py);
up(root);
} void change(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
flag[root]=1;
f[root].sy=f[root].sx=(double)(r+l)*(double)(r-l+1)/2.0;
f[root].xy=f[root].sqr=(double)(r+1)*(double)r*(double)(2*r+1)/6.0-(double)(l-1)*(double)l*(double)(2*l-1)/6.0;
add[root].x=add[root].y=0;
return;
}
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) change(2*root,l,mid,x,y);
if (y>mid) change(2*root+1,mid+1,r,x,y);
up(root);
}

求答案的部分就不放了

其他的emmmm 也很裸 直接上全部的代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector> using namespace std; inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} const int maxn = 3e5+1e2; struct Node{
double sx,sy,sqr,xy,sum;
}; struct po{
double x,y;
}; Node f[4*maxn];
po add[4*maxn],a[maxn];
bool flag[4*maxn];
int n,m; void up(int root)
{
f[root].sx=f[2*root].sx+f[2*root+1].sx;
f[root].sy=f[2*root].sy+f[2*root+1].sy;
f[root].sqr=f[2*root].sqr+f[2*root+1].sqr;
f[root].xy=f[2*root].xy+f[2*root+1].xy;
// f[root].sum=f[2*root].sum+f[2*root+1].sum;
} void pushdown(int root,int ll,int rr)
{
double mid = (ll+rr)/2;
double l=ll,r=rr;
if (flag[root])
{
flag[2*root+1]=1;flag[2*root]=1;flag[root]=0;add[2*root].x=add[2*root].y=add[2*root+1].x=add[2*root+1].y=0;
f[2*root].sx=(l+mid)*(mid-l+1)/2;
f[2*root].sy=(l+mid)*(mid-l+1)/2;
f[2*root+1].sx=(r+mid+1)*(r-mid-1+1)/2;
f[2*root+1].sy=(r+mid+1)*(r-mid-1+1)/2;
f[2*root].xy=f[2*root].sqr=(mid+1)*mid*(2*mid+1)/6-(l-1)*l*(2*l-1)/6;
f[2*root+1].xy=f[2*root+1].sqr=(r+1)*r*(2*r+1)/6-(mid)*(mid+1)*(2*mid+1)/6;
}
if (add[root].x || add[root].y)
{
add[2*root].x+=add[root].x;
add[2*root+1].x+=add[root].x;
add[2*root].y+=add[root].y;
add[2*root+1].y+=add[root].y;
f[2*root].sqr+=(mid-l+1)*add[root].x*add[root].x+2*f[2*root].sx*add[root].x;
f[2*root+1].sqr+=(r-mid)*add[root].x*add[root].x+2*f[2*root+1].sx*add[root].x;
f[2*root].xy+=(mid-l+1)*add[root].x*add[root].y+f[2*root].sx*add[root].y+f[2*root].sy*add[root].x;
f[2*root+1].xy+=(r-mid)*add[root].x*add[root].y+f[2*root+1].sx*add[root].y+f[2*root+1].sy*add[root].x;
f[2*root].sx+=(mid-l+1)*add[root].x;
f[2*root+1].sx+=(r-mid)*add[root].x;
f[2*root].sy+=(mid-l+1)*add[root].y;
f[2*root+1].sy+=(r-mid)*add[root].y;
add[root].x=0;
add[root].y=0;
}
} void build(int root,int l,int r)
{
if (l==r)
{
f[root].sx=a[l].x;
f[root].sy=a[l].y;
f[root].xy=a[l].x*a[l].y;
f[root].sqr=a[l].x*a[l].x;
return;
}
int mid = (l+r) >> 1;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
up(root);
} void update(int root,int l,int r,int x,int y,double px,double py)
{
if (x<=l && r<=y)
{
add[root].x+=px;
add[root].y+=py;
f[root].xy+=(double)(r-l+1)*px*py+(double)f[root].sx*py+(double)f[root].sy*px;
f[root].sqr+=(double)(r-l+1)*px*px+(double)f[root].sx*px*2;
f[root].sx+=(double)(r-l+1)*px;
f[root].sy+=(double)(r-l+1)*py;
return;
}
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) update(2*root,l,mid,x,y,px,py);
if (y>mid) update(2*root+1,mid+1,r,x,y,px,py);
up(root);
} void change(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
flag[root]=1;
f[root].sy=f[root].sx=(double)(r+l)*(double)(r-l+1)/2.0;
f[root].xy=f[root].sqr=(double)(r+1)*(double)r*(double)(2*r+1)/6.0-(double)(l-1)*(double)l*(double)(2*l-1)/6.0;
add[root].x=add[root].y=0;
return;
}
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) change(2*root,l,mid,x,y);
if (y>mid) change(2*root+1,mid+1,r,x,y);
up(root);
} double queryxy(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
return f[root].xy;
}
pushdown(root,l,r);
int mid = (l+r)>>1;
double ans=0;
if (x<=mid) ans+=queryxy(2*root,l,mid,x,y);
if (y>mid) ans+=queryxy(2*root+1,mid+1,r,x,y);
return ans;
} double querysqr(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
return f[root].sqr;
}
pushdown(root,l,r);
int mid = (l+r)>>1;
double ans=0;
if (x<=mid) ans+=querysqr(2*root,l,mid,x,y);
if (y>mid) ans+=querysqr(2*root+1,mid+1,r,x,y);
return ans;
} double querysx(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
return f[root].sx;
}
pushdown(root,l,r);
int mid = (l+r)>>1;
double ans=0;
if (x<=mid) ans+=querysx(2*root,l,mid,x,y);
if (y>mid) ans+=querysx(2*root+1,mid+1,r,x,y);
return ans;
} double querysy(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
return f[root].sy;
}
pushdown(root,l,r);
int mid = (l+r)>>1;
double ans=0;
if (x<=mid) ans+=querysy(2*root,l,mid,x,y);
if (y>mid) ans+=querysy(2*root+1,mid+1,r,x,y);
return ans;
} double solve(int l,int r)
{
double ax = querysx(1,1,n,l,r)/(double)(r-l+1);
double ay = querysy(1,1,n,l,r)/(double)(r-l+1);
update(1,1,n,l,r,-ax,-ay);
double ans = queryxy(1,1,n,l,r)/querysqr(1,1,n,l,r);
update(1,1,n,l,r,ax,ay);
return ans;
} int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lf",&a[i].x);
for (int i=1;i<=n;i++) scanf("%lf",&a[i].y);
build(1,1,n);
for (int i=1;i<=m;i++)
{
int opt;
int x,y;
double px,py;
opt=read();
if (opt==1)
{
x=read(),y=read();printf("%.10lf\n",solve(x,y));
}
if (opt==2)
{
x=read(),y=read();
scanf("%lf%lf",&px,&py);
update(1,1,n,x,y,px,py);
}
if (opt==3)
{
x=read(),y=read();
scanf("%lf%lf",&px,&py);
change(1,1,n,x,y);
update(1,1,n,x,y,px,py);
}
}
return 0;
}

QwQ共勉

bzoj4821 && luogu3707 SDOI2017相关分析(线段树,数学)的更多相关文章

  1. 【BZOJ4821】[Sdoi2017]相关分析 线段树

    [BZOJ4821][Sdoi2017]相关分析 Description Frank对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. ...

  2. [Sdoi2017]相关分析 [线段树]

    [Sdoi2017]相关分析 题意:沙茶线段树 md其实我考场上还剩一个多小时写了40分 其实当时写正解也可以吧1h也就写完了不过还要拍一下 正解代码比40分短2333 #include <io ...

  3. BZOJ 4821 [Sdoi2017]相关分析 ——线段树

    打开题面,看到许多$\sum$ woc,好神啊,SDOI好强啊 然后展开之后,woc,SDOI好弱啊,怎么T3出个线段树裸题啊. 最后写代码的时候,woc,SDOI怎么出个这么码农的题啊,怎么调啊. ...

  4. 洛谷P3707 [SDOI2017]相关分析(线段树)

    题目描述 Frank对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. Frank不仅喜欢观测,还喜欢分析观测到的数据.他经常分析两个 ...

  5. BZOJ 4821: [Sdoi2017]相关分析 线段树 + 卡精

    考试的时候切掉了,然而卡精 + 有一个地方忘开 $long long$,完美挂掉 $50$pts. 把式子化简一下,然后直接拿线段树来维护即可. Code: // luogu-judger-enabl ...

  6. BZOJ.4821.[SDOI2017]相关分析(线段树)

    BZOJ LOJ 洛谷 恶心的拆式子..然后就是要维护\(\sum x_i,\ \sum y_i,\ \sum x_iy_i,\ \sum x_i^2\). 操作三可以看成初始化一遍,然后同操作二. ...

  7. SDOI2017相关分析 线段树

    题目 https://loj.ac/problem/2005 思路 \[ \sum_{L}^{R}{(x_i-x)^{2}} \] \[ \sum_{L}^{R}{(x_i^2-2*x_i*x+x^{ ...

  8. 【BZOJ4821】[SDOI2017]相关分析(线段树)

    [BZOJ4821][SDOI2017]相关分析(线段树) 题面 BZOJ 洛谷 题解 看看询问要求的东西是什么.把所有的括号拆开,不难发现要求的就是\(\sum x,\sum y,\sum xy,\ ...

  9. 【BZOJ4821】【SDOI2017】相关分析 [线段树]

    相关分析 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Frank对天文学非常感兴趣,他经 ...

随机推荐

  1. 小程序生成商品分享二维码海报解决方案和实现方式JAVA

    使用技术:  Graphics , 七牛云 , 微信sdk(github上非常出名的wxjava,地址https://github.com/Wechat-Group/WxJava/)直接上干货代码,每 ...

  2. python操作图片

    时间:2018-11-30 记录:byzqy 标题:python实现图片操作 地址:https://blog.csdn.net/baidu_34045013/article/details/79187 ...

  3. Elasticsearch集群搭建教程及生产环境配置

    Elasticsearch 是一个极其强大的搜索和分析引擎,其强大的部分在于能够对其进行扩展以获得更好的性能和稳定性. 本教程将提供有关如何设置 Elasticsearch 集群的一些信息,并将添加一 ...

  4. Ajax技术---核心XMLHttpRequest对象

    Ajax 的全称是Asynchronous JavaScript and XML,其中,Asynchronous 是异步的意思,它有别于传统web开发中采用的同步的方式. (一)ajax技术的意义 我 ...

  5. 【Python机器学习实战】决策树与集成学习(五)——集成学习(3)GBDT应用实例

    前面对GBDT的算法原理进行了描述,通过前文了解到GBDT是以回归树为基分类器的集成学习模型,既可以做分类,也可以做回归,由于GBDT设计很多CART决策树相关内容,就暂不对其算法流程进行实现,本节就 ...

  6. vue-过滤器(filter)的使用详解

    前言 Vue 允许我们在项目中定义过滤器对我们页面的文本展示进行格式的控制,本文就来总结一下过滤器在项目中的常见使用方法. 正文 1.局部过滤器的注册 (1)无参局部过滤器 <div id=&q ...

  7. 运输层协议:TCP连接建立与释放

    TCP的特点 面向连接:TCP是面向连接的运输层协议,通过TCP发送数据需要先建立连接,通信结束后需要释放连接 可靠传输:TCP实现了可靠传输,使得数据能够无丢失.无差错.不重复地到达接收端 面向字节 ...

  8. SNMP协议之序言

    最近两周公司分配一个任务:使用snmp协议做一个网管,来配置我们的产品.这可以说是我第一次听说这个协议,我问了一下周围的同事这是个什么协议,同事说"简单网络管理协议",其实这个协议 ...

  9. java版gRPC实战之三:服务端流

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  10. Java数值传递的时候,到底是引用传递还是值传递

    java中既有引用传递也有值传递 ---->>方法形式参数上 1.值传递,基本数据类型 值传递是:传递的是存储单元中的内容,而不是存储单元的引用. 2.引用传递:引用类型,数组,集合. 引 ...