[Luogu 3707] SDOI2017 相关分析

<题目链接>


前言

Capella 和 Frank 一样爱好天文学。

她常在冬季的夜晚,若有所思地望着东北方上空的五边形中,最为耀眼的一个顶点。

那一抹金黄曾带给她多少美好的遐想!

直到有一天,她做了这一题,并饱受线段树的折磨。

概述

这是一道区间操作的题目,解法有线段树与分块等。

题主选择线段树进行讲解(因为没用分块写这题)。

准备与计算答案

首先要知道,线段树需要维护的数值有哪些。

先来看题目中所给的公式。

\(\bar x = \frac 1 {r-l+1} \sum_{i=l}^r x_i\)

\(\bar y = \frac 1 {r-l+1} \sum_{i=l}^r y_i\)

\(\hat a = \frac{\sum_{i=l}^r (x_i - \bar x)(y_i - \bar y)}{\sum_{i=l}^r (x_i - \bar x)^2}\)

将线性回归方程的公式展开得(\(\sum_{i=l}^r\) 省略为 \(\sum\)):

\(\hat a = \frac{\sum (x_i y_i - \bar x y_i - \bar y x_i + \bar x \bar y)}
{\sum (x_i^2 - 2\bar x x_i + \bar x^2)}\)

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

将 \(\bar x\)、\(\bar y\) 代入上式得:

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

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

由此可见,线段树需要维护的数值有 \(\sum x_i^2\)、\(\sum x_i y_i\)、\(\sum x_i\) 以及 \(\sum y_i\)。

设 \(v_0 = \sum x_i^2, v_1 = \sum x_i y_i, v_2 = \sum x_i, v_3 = \sum y_i\),

则最终计算出的 \(\hat a = \frac{v_1 - \frac{v_2 v_3}{r-l+1}}{v_0 - \frac{v_2^2}{r-l+1}}\)。

区间加操作

进行区间加操作时,设 \(x\) 的变化量为 \(S\),\(y\) 的变化量为 \(T\),则各个标记的下传过程如下:

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

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

\(\sum (x_i+S)(y_i+T) = \sum (x_i y_i + Sy_i+Tx_i+ST)\)

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

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

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

特别注意:由于更新 $\sum x_i^2 $ 与 \(\sum x_i y_i\) 时,需要用到更新前的 \(\sum x_i\) 与 \(\sum y_i\) 的值,所以应注意顺序

区间修改操作

前置技能

\(1^2 + 2^2 + \dots + n^2 = \frac {n(n+1)(2n+1)} 6\)

转化

试图将区间修改操作转化为区间加操作。

对于 \(i \in [l,r]\),\(x_i\) 改为 \(S+i\),\(y_i\) 改为 \(T+i\),

相当于将 \(i \in [l,r]\) 的每个 \(x_i\) 与 \(y_i\) 都改为 \(i\) ,

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

\(\sum x_i = \sum y_i = \sum i = \frac {(r-l+1)(l+r)} 2\)(\(r-l+1\) 为区间元素个数,\(\frac {l+r} 2\) 为区间平均值)

然后清空Lazy Tag(无论区间曾经加了多少都没有用,将被统一修改)。

维护操作

清空Lazy Tag后,对区间 \([l,r]\) 进行区间加操作,即:每个 \(x_i\) 加上 \(S\),每个 \(y_i\) 加上 \(T\)。

更新过程与区间加操作完全相同。

最后还要打上标记c,表示此区间的子区间需要区间修改操作。

注意事项

  • 一定记得下传Lazy Tagc标记,我就是因为没传才调了一上午+一下午+半个晚上的。

  • 本题下传标记部分较为复杂,请一定注意顺序

结束语

这道题有点像《HAOI2012 高速公路》啊。

线段树这种东西,多推一推也就熟悉啦。

加油,各位队友;加油,自己。

#include <cstdio>
#include <cstring>
const int MAXN=100010;
double x[MAXN],y[MAXN];
int n,m;
class SegmentTree
{
public:
void Build(int i,int l,int r)
{
s[i]=node(l,r);
if(l==r)
{
s[i].v[0]=x[l]*x[l],s[i].v[1]=x[l]*y[r],s[i].v[2]=x[l],s[i].v[3]=y[r];
return;
}
int j=i<<1,mid=l+r>>1;
Build(j,l,mid),Build(j|1,mid+1,r),PushUp(i);
}
void Add(int i,int l,int r,double S,double T)
{
if(l==s[i].l && r==s[i].r)
{
AddModify(i,S,T);
return;
}
if(s[i].l^s[i].r)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
Add(j,l,r,S,T);
else if(l>mid)
Add(j|1,l,r,S,T);
else
Add(j,l,mid,S,T),Add(j|1,mid+1,r,S,T);
PushUp(i);
}
void Change(int i,int l,int r,double S,double T)
{
if(l==s[i].l && r==s[i].r)
{
ChangeModify(i),AddModify(i,S,T);
return;
}
if(s[i].l^s[i].r)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
Change(j,l,r,S,T);
else if(l>mid)
Change(j|1,l,r,S,T);
else
Change(j,l,mid,S,T),Change(j|1,mid+1,r,S,T);
PushUp(i);
}
double Ans(double l,double r)
{
double size=r-l+1;
memset(ans,0,sizeof ans);
Sum(1,l,r);
return (ans[1]-ans[2]*ans[3]/size)/(ans[0]-ans[2]*ans[2]/size);
}
private:
double ans[4];
struct node
{
bool c;
double S,T,v[4];
int l,r;
node(int _l=0,int _r=0)
{
l=_l,r=_r,c=S=T=0;
}
}s[MAXN<<2];
double Calc(double i)
{
return i*(i+1)*(2*i+1)/6;
}
void AddModify(int i,double S,double T)
{
double size=double(s[i].r-s[i].l+1);
s[i].v[0]+=S*S*size+2*S*s[i].v[2];
s[i].v[1]+=S*T*size+S*s[i].v[3]+T*s[i].v[2];
s[i].v[2]+=S*size;
s[i].v[3]+=T*size;
s[i].S+=S,s[i].T+=T;
}
void ChangeModify(int i)
{
double l=double(s[i].l),r=double(s[i].r);
s[i].v[0]=s[i].v[1]=Calc(r)-Calc(l-1),s[i].v[2]=s[i].v[3]=(r-l+1)*(l+r)/2,s[i].c=1,s[i].S=s[i].T=0;
}
void PushUp(int i)
{
int l=i<<1,r=l|1;
for(int k=0;k<4;++k)
s[i].v[k]=s[l].v[k]+s[r].v[k];
}
void PushDown(int i)
{
int l=i<<1,r=l|1;
if(s[i].c)
ChangeModify(l),ChangeModify(r);
AddModify(l,s[i].S,s[i].T),AddModify(r,s[i].S,s[i].T);
s[i].c=s[i].S=s[i].T=0;
}
void Sum(int i,int l,int r)
{
if(l==s[i].l && r==s[i].r)
{
for(int k=0;k<4;++k)
ans[k]+=s[i].v[k];
return;
}
if(s[i].l^s[i].r)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
Sum(j,l,r);
else if(l>mid)
Sum(j|1,l,r);
else
Sum(j,l,mid),Sum(j|1,mid+1,r);
}
}SgT;
int main(int argc,char *argv[])
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lf",&x[i]);
for(int i=1;i<=n;++i)
scanf("%lf",&y[i]);
SgT.Build(1,1,n);
for(int i=1,opt,l,r;i<=m;++i)
{
double S,T;
scanf("%d %d %d",&opt,&l,&r);
switch(opt)
{
case 1:
printf("%.10lf\n",SgT.Ans(l,r));
break;
case 2:
scanf("%lf %lf",&S,&T);
SgT.Add(1,l,r,S,T);
break;
case 3:
scanf("%lf %lf",&S,&T);
SgT.Change(1,l,r,S,T);
break;
}
}
return 0;
}

谢谢阅读。

[Luogu 3707] SDOI2017 相关分析的更多相关文章

  1. [题目] Luogu P3707 [SDOI2017]相关分析

    参考资料:[Luogu 3707] SDOI2017 相关分析 P3707 [SDOI2017]相关分析 TFRAC FRAC DFRAC \(\tfrac{\sum}{1}\) \(\frac{\s ...

  2. 洛谷3707 [SDOI2017] 相关分析 【线段树】

    分析: 化简一下就行了,注意一下平方和公式的运用以及精度的误差. 代码: #include<bits/stdc++.h> using namespace std; ; int n,m; i ...

  3. luogu P3707 [SDOI2017]相关分析

    传送门 对于题目要求的东西,考虑拆开懒得拆了 ,可以发现有\(\sum x\sum y\sum x^2\sum xy\)四个变量影响最终结果,考虑维护这些值 下面记\(l,r\)为区间两端点 首先是区 ...

  4. P3707 [SDOI2017]相关分析

    P3707 [SDOI2017]相关分析 线段树裸题?但是真的很麻烦QAQ 题目给的式子是什么不用管,大力拆开,就是\(\frac{\sum x_iy_i-\overline xy_i-\overli ...

  5. BZOJ4817 SDOI2017 相关分析

    4821: [Sdoi2017]相关分析 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special Judge Description Frank对天文 ...

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

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

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

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

  8. 4821: [Sdoi2017]相关分析

    4821: [Sdoi2017]相关分析 链接 分析: 大力拆式子,化简,然后线段树.注意精度问题与爆longlong问题. 代码: #include<cstdio> #include&l ...

  9. AC日记——[SDOI2017]相关分析 洛谷 P3707

    [SDOI2017]相关分析 思路: 裸线段树: (玄学ac): 代码: #include <bits/stdc++.h> using namespace std; #define max ...

随机推荐

  1. MFC获取系统信息

    一.获取系统时间 CString str,str2; CTime time; time = CTime::GetCurrentTime(); str = time.Format("%Y年%m ...

  2. thinkphp 百度编辑器和layer简单用法

    百度编辑器1.4.3.3和layer插件简单案例 :后台单页面管理 增删改查操作 此处为默认图片保存路径,如果要修改保存路径,需要修改config文件. 添加页. <extend name=&q ...

  3. Eclipse 中设置JVM 内存

    Eclipse 中设置JVM 内存 今天在eclipse 中测试把文档转换为图片的时候,报出了下面的错误: java.lang.OutOfMemoryError: Java heap space 从上 ...

  4. Spring Security(二)

    Spring Security(二) 注:凡是源码部分,我已经把英文注释去掉了,有兴趣的同学可以在自己项目里进去看看.:-) 定义用户认证逻辑 用户登录成功后,用户的信息会被 Security 封装在 ...

  5. Freemarker出现NullNumberException异常

    Spring Boot项目使用了Freemarker模板引擎. 在ftl文件中使用了一些变量,但是一直出现错误,无法正常渲染页面,反复出现的报错是: freemarker.core.NonNumeri ...

  6. Java 基础:变量 与 字符串

    变量 Java中没有初始化的变量是不能直接使用的 局部变量 String msg; System.out.print(msg); 就会提示错误,我们必须显式的为变量指定一个初值如null.刚开始学Ja ...

  7. w3school前端教程合集

    有关前端开发的w3c教程合集. http://caibaojian.com/w3school/ 地图 ajax教程 Canvas教程 CSS教程 CSS3教程 CSS3选择器 CSS参考手册 DHTM ...

  8. node 静态伺服(搭建服务)

    基本功能 不急着写下第一行代码,而是先梳理一下就基本功能而言有哪些步骤. 在本地根据指定端口启动一个http server,等待着来自客户端的请求 当请求抵达时,根据请求的url,以设置的静态文件目录 ...

  9. Jquery 清除空白字符

    $.grep(“jQuery数组”, function(n) { return $.trim(n).length > 0; }); /*仅过滤空数组,不过滤相同数组*/

  10. SQLServer 中的身份验证及登录问题

    SQLServer 中的身份验证及登录问题 by:授客 QQ:1033553122 身份验证 SQL Server 支持两种身份验证模式,即Windows 身份验证模式和混合模式. Windows 身 ...