【SDOI2017】相关分析(线段树)
Description
你需要维护一个长度为 \(n\) 的实数对的序列,第 \(i\) 个元素为 \((x_i, y_i)\)。现有 \(m\) 次操作:
- \(\texttt{1 L R}\):设区间 \([L, R]\) 的平均数 \(\bar x = \frac{\sum_{i=L}^R x_i}{R-L+1},\bar y = \frac{\sum_{i=L}^R y_i}{R-L+1}\),求
\]
的值。误差不超过 \(10^{-5}\)。
\(\texttt{2 L R S T}\):进行如下修改:
\(\forall i\in[L, R],\quad x_i \leftarrow x_i + S\)
\(\forall i\in[L, R],\quad y_i \leftarrow y_i + T\)
\(\texttt{3 L R S T}\):进行如下修改:
\(\forall i \in [L, R],\quad x_i \leftarrow i + S\)
\(\forall i \in [L, R],\quad y_i \leftarrow i + T\)
Hint
\(1\le n, m\le 10^5, 0\le |S|, |T|\le 10^5, 0\le |x_i|, |y_i|\le 10^5\)
Solution
一道细节很多的线段树练手题。
在考虑怎么支持这些操作时不妨先看看我们需要维护些什么东西。拆开 \(a\) 这个柿子:
(下面用 \(\sum\) 代替 \(\sum_{i=L}^R\),用 \(n\) 代替 \(R - L + 1\))
a = & \dfrac{\sum (x_i - \bar x)(y_i - \bar y)}{\sum (x_i - \bar x)^2} = \dfrac A B \\ \\
A = & \sum (x_i y_i - x_i \bar y - y_i \bar x_i + \bar x \bar y) \\
= & \sum x_i y_i - \bar y\sum x_i - \bar x\sum y_i + n\bar x \bar y \\
= & \sum x_i y_i - \tfrac{1}{n}\sum x_i \sum y_i \\ \\
B = & \sum (x_i^2 + {\bar x}^2 - 2x_i\bar x) \\
= & \sum x_i^2 +n{\bar x}^2 - 2\bar x\sum x_i \\
= & \sum x_i^2 -\tfrac{1}{n}\left(\sum x_i\right)^2\\
\end{aligned}
\]
将 \(\bar x, \bar y\) 展开的话,可以发现我们需要维护四个东西:
A = & \boxed{\sum x_i y_i} - \tfrac{1}{n}\boxed{\sum x_i}\times \boxed{\sum y_i} \\
B = & \boxed{\sum x_i^2} -\tfrac{1}{n}\left(\sum x_i\right)^2\\
\end{aligned}
\]
整坨柿子瞬间简洁可做了。
那么如何维护这四个信息呢?为了方便,我们用 \(v_1, v_2, v_3, v_4\) 分别代表 \(\sum x_i, \sum y_i,\sum x_i^2,\sum x_i y_i\)。
考虑修改操作之后这四个信息的变化:
- 操作 \(2\):
&\sum x_i\to\sum(x_i+S)=\sum x_i+nS & v_1\to v_1 + nS \\
&\sum y_i\to\sum(y_i+T)=\sum y_i+nT & v_2\to v_2 + nT \\
&\sum x_i^2\to\sum(x_i+S)^2=\sum x_i^2+nS^2+2S\sum x_i& v_3\to v_3+nS^2+2Sv_1\\
&\sum x_i y_i \to\sum(x_i+S)(y_i+T)=\sum x_i y_i+T\sum x_i+S\sum y_i+nST & v_4 \to v_4+Tv_1+Sv_2+nST\\
\end{aligned}
\]
- 操作 \(3\):
- 记 \(s_1 = \sum_{i=L}^R i, s_2 = \sum_{i=L}^R i^2\)。
&\sum x_i\to\sum(i+S)=s_1+nS & v_1\to s_1 + nS \\
&\sum y_i\to\sum(i+T)=s_1+nT & v_2\to s_1 + nT \\
&\sum x_i^2\to\sum(i+S)^2=s_2+nS^2+2Ss_1& v_3\to s_2+nS^2+2Ss_1\\
&\sum x_i y_i \to\sum(i+S)(i+T)=s_2+(T+S)s_1+nST & v_4 \to s_2+(T+S)s_1+nST\\
\end{aligned}
\]
于是就这样维护就行了,注意操作二的更新顺序。
其中 \(s_1, s_2\) 的计算可以预处理,也可以直接使用公式:
- \(\sum_{j=1}^i j = \frac{i(i+1)}{2}\)
- \(\sum_{j=1}^i j^2 = \frac{i(i+1)(2i+1)}{6}\)
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : SDOI2017 相关分析
*/
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int N = 1e5 + 5;
const int S = N << 2;
namespace calculator {
inline double sum(const double& l, const double& r) {
return (l + r) * (r - l + 1) / 2;
}
inline double sqrs(const double& p) {
return p * (p + 1) * (2 * p + 1) / 6;
}
}
struct dataType {
double sumx, sumy, sqrs, muls;
inline dataType()
: sumx(0.0), sumy(0.0), sqrs(0.0), muls(0.0) { }
inline dataType(const double& a, const double& b,
const double& c, const double& d)
: sumx(a), sumy(b), sqrs(c), muls(d) { }
inline dataType(const double& x, const double& y)
: sumx(x), sumy(y), sqrs(x * x), muls(x * y) { }
inline dataType operator + (const dataType& rhs) const {
return dataType(this->sumx + rhs.sumx, this->sumy + rhs.sumy,
this->sqrs + rhs.sqrs, this->muls + rhs.muls);
}
inline void update(const dataType& rhs) {
this->sumx += rhs.sumx, this->sumy += rhs.sumy;
this->sqrs += rhs.sqrs, this->muls += rhs.muls;
}
};
struct tagType {
double S, T;
inline tagType()
: S(0.0), T(0.0) { }
inline tagType(const double& s, const double& t)
: S(s), T(t) { }
inline bool operator == (const tagType& rhs) const {
return (fabs(this->S - rhs.S) <= 1e-8) && (fabs(this->T - rhs.T) <= 1e-8);
}
inline bool operator != (const tagType& rhs) const {
return !(*this == rhs);
}
};
const tagType std_cov(-1e18, -1e18);
const tagType std_add(0, 0);
int L[S], R[S];
dataType tr[S];
tagType cov[S];
tagType add[S];
#define mid ((L[x] + R[x]) / 2)
#define len double(R[x] - L[x] + 1)
inline void pushup(int x) {
tr[x] = tr[x << 1] + tr[x << 1 | 1];
}
inline void setCov(int x, const tagType& v) {
double s1 = calculator::sum(L[x], R[x]);
double s2 = calculator::sqrs(R[x]) - calculator::sqrs(L[x] - 1);
tr[x].sqrs = s2 + len * v.S * v.S + 2 * v.S * s1;
tr[x].muls = s2 + (v.S + v.T) * s1 + len * v.S * v.T;
tr[x].sumx = s1 + len * v.S;
tr[x].sumy = s1 + len * v.T;
cov[x] = v, add[x] = std_add;
}
inline void setAdd(int x, const tagType& v) {
tr[x].sqrs += v.S * v.S * len + 2 * v.S * tr[x].sumx;
tr[x].muls += v.S * tr[x].sumy + v.T * tr[x].sumx + len * v.S * v.T;
tr[x].sumx += v.S * len, tr[x].sumy += v.T * len;
add[x].S += v.S, add[x].T += v.T;
}
inline void pushdown(int x) {
if (cov[x] != std_cov) {
setCov(x << 1, cov[x]);
setCov(x << 1 | 1, cov[x]);
cov[x] = std_cov;
}
if (add[x] != std_add) {
setAdd(x << 1, add[x]);
setAdd(x << 1 | 1, add[x]);
add[x] = std_add;
}
}
void build(int x, int l, int r, double* datx, double* daty) {
L[x] = l, R[x] = r;
cov[x] = std_cov, add[x] = std_add;
if (l == r) {
tr[x] = dataType(datx[l], daty[l]);
return;
}
build(x << 1, l, mid, datx, daty);
build(x << 1 | 1, mid + 1, r, datx, daty);
pushup(x);
}
void modify(int x, int l, int r, void(*update)(int, const tagType&), const tagType& v) {
if (l <= L[x] && R[x] <= r) return update(x, v);
pushdown(x);
if (l <= mid) modify(x << 1, l, r, update, v);
if (r > mid) modify(x << 1 | 1, l, r, update, v);
pushup(x);
}
void query(int x, int l, int r, dataType& ret) {
if (l <= L[x] && R[x] <= r) return ret.update(tr[x]);
if (l > R[x] || L[x] > r) return;
pushdown(x), query(x << 1, l, r, ret), query(x << 1 | 1, l, r, ret);
}
#undef mid
#undef len
int n, Q;
double x[N], y[N];
signed main() {
scanf("%d%d", &n, &Q);
for (int i = 1; i <= n; i++) scanf("%lf", x + i);
for (int i = 1; i <= n; i++) scanf("%lf", y + i);
build(1, 1, n, x, y);
while (Q--) {
int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if (opt == 1) {
dataType res; query(1, l, r, res);
double len = r - l + 1;
double avex = res.sumx / len;
double avey = res.sumy / len;
double A = res.muls - res.sumx * res.sumy / len;
double B = res.sqrs - res.sumx * res.sumx / len;
printf("%lf\n", A / B);
} else {
tagType val; scanf("%lf%lf", &val.S, &val.T);
modify(1, l, r, (opt == 2 ? setAdd : setCov), val);
}
}
}
【SDOI2017】相关分析(线段树)的更多相关文章
- [Sdoi2017]相关分析 [线段树]
[Sdoi2017]相关分析 题意:沙茶线段树 md其实我考场上还剩一个多小时写了40分 其实当时写正解也可以吧1h也就写完了不过还要拍一下 正解代码比40分短2333 #include <io ...
- 【BZOJ4821】[Sdoi2017]相关分析 线段树
[BZOJ4821][Sdoi2017]相关分析 Description Frank对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. ...
- BZOJ 4821 [Sdoi2017]相关分析 ——线段树
打开题面,看到许多$\sum$ woc,好神啊,SDOI好强啊 然后展开之后,woc,SDOI好弱啊,怎么T3出个线段树裸题啊. 最后写代码的时候,woc,SDOI怎么出个这么码农的题啊,怎么调啊. ...
- 洛谷P3707 [SDOI2017]相关分析(线段树)
题目描述 Frank对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. Frank不仅喜欢观测,还喜欢分析观测到的数据.他经常分析两个 ...
- BZOJ 4821: [Sdoi2017]相关分析 线段树 + 卡精
考试的时候切掉了,然而卡精 + 有一个地方忘开 $long long$,完美挂掉 $50$pts. 把式子化简一下,然后直接拿线段树来维护即可. Code: // luogu-judger-enabl ...
- BZOJ.4821.[SDOI2017]相关分析(线段树)
BZOJ LOJ 洛谷 恶心的拆式子..然后就是要维护\(\sum x_i,\ \sum y_i,\ \sum x_iy_i,\ \sum x_i^2\). 操作三可以看成初始化一遍,然后同操作二. ...
- SDOI2017相关分析 线段树
题目 https://loj.ac/problem/2005 思路 \[ \sum_{L}^{R}{(x_i-x)^{2}} \] \[ \sum_{L}^{R}{(x_i^2-2*x_i*x+x^{ ...
- 【BZOJ4821】【SDOI2017】相关分析 [线段树]
相关分析 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description Frank对天文学非常感兴趣,他经 ...
- luogu3707 相关分析 (线段树)
把式子展开以后会发现,可以用线段树维护$x,y,x*y,x^2$分别的区间和 然后操作有区间加和区间修改 这个pushdown的时候,如果改和加的标记同时存在,那一定是先改再加,要不然加的标记已经被清 ...
- LOJ #2005. 「SDOI2017」相关分析 线段树维护回归直线方程
题目描述 \(Frank\) 对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. \(Frank\) 不仅喜欢观测,还喜欢分析观测到的 ...
随机推荐
- 流编辑器:sed
一 简介:sed是一个精简的.非交互式的流式编辑器,它在命令行中输入编辑命令和指定文件名,然后在屏幕上查看输出.逐行读取文件内容到临时缓冲区,称为模式空间.接着用sed命令处理缓冲区内容,处理完之后, ...
- Redis在springboot项目的使用
一.在pom.xml配置redis依赖 <!-- redis客户端代码 --> <dependency> <groupId>org.springframework. ...
- rados put striper功能的调试
前言 之前对于striper这个地方的功能并没研究太多,只是知道这个里面可以以条带方式并行的去写对象,从而加大并发性来提高性能,而默认的条带数目为1,也就是以对象大小去写,并没有条带,所以不是很好感觉 ...
- Mac 安装并破解热部署插件JRebel详细教程
热部署插件 JRebel 非常高效的解决了在IDEA中对 Java 代码修改重启Tomcat的效率问题,这样大大降低了项目开发的时间,不用重启即可重新编译修改过的Java代码! (1)IDEA中安装热 ...
- 三步删除U深度,老毛桃,大白菜捆绑软件!!
①需要下载一个软件Fbinst Tool(万能U盘制作工具).链接:http://pan.baidu.com/s/1mim9Zxm 密码:7poo②插入U盘,直接打开Fbinst Tool.首先是U深 ...
- nginx转发php文件到php-fpm服务器提示502错误
实验将php文件转发给另一个php-fpm服务器处理的时候,出现了502错误: 检查了nginx错误日志,提示: 2019/08/25 17:54:56 [error] 4742#0: *35 rec ...
- 【MathType教学】如何让括号内的内容居中
作为一款非常好用的公式编辑器,MathType它的功能十分强大,不仅包含了大量的数学符号,并且能和Office软件很好地兼容.但是有的时候打出来的公式可能不是自己想要的效果,这时我们就要用一些特别的办 ...
- Contest 991
A 先判合法然后容斥. 时间复杂度 \(O\left(1\right)\). B 贪心选最小的实验做成 \(5\) 分. 时间复杂度 \(O\left(n\right)\). 剩下的鸽了.
- 【数据结构模版】可持久化线段树 && 主席树
浙江集训Day4,从早8:00懵B到晚21:00,只搞懂了可持久化线段树以及主席树的板子.今天只能记个大概,以后详细完善讲解. 可持久化线段树指的是一种基于线段树的可回溯历史状态的数据结构.我们想要保 ...
- Java反射——读取XML文件,创建对象
读取XML文件,创建对象 config.xml <?xml version="1.0" encoding="UTF-8"?> <beans&g ...