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}\),求
\[a = \dfrac{\sum_{i=L}^R (x_i - \bar x)(y_i - \bar y)}{\sum_{i=L}^R (x_i - \bar x)^2}
\]

的值。误差不超过 \(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\))

\[\begin{aligned}
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\) 展开的话,可以发现我们需要维护四个东西:

\[\begin{aligned}
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\):
\[\begin{aligned}
&\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\)。
\[\begin{aligned}
&\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

  1. /*
  2. * Author : _Wallace_
  3. * Source : https://www.cnblogs.com/-Wallace-/
  4. * Problem : SDOI2017 相关分析
  5. */
  6. #include <algorithm>
  7. #include <cmath>
  8. #include <cstdio>
  9. using namespace std;
  10. const int N = 1e5 + 5;
  11. const int S = N << 2;
  12. namespace calculator {
  13. inline double sum(const double& l, const double& r) {
  14. return (l + r) * (r - l + 1) / 2;
  15. }
  16. inline double sqrs(const double& p) {
  17. return p * (p + 1) * (2 * p + 1) / 6;
  18. }
  19. }
  20. struct dataType {
  21. double sumx, sumy, sqrs, muls;
  22. inline dataType()
  23. : sumx(0.0), sumy(0.0), sqrs(0.0), muls(0.0) { }
  24. inline dataType(const double& a, const double& b,
  25. const double& c, const double& d)
  26. : sumx(a), sumy(b), sqrs(c), muls(d) { }
  27. inline dataType(const double& x, const double& y)
  28. : sumx(x), sumy(y), sqrs(x * x), muls(x * y) { }
  29. inline dataType operator + (const dataType& rhs) const {
  30. return dataType(this->sumx + rhs.sumx, this->sumy + rhs.sumy,
  31. this->sqrs + rhs.sqrs, this->muls + rhs.muls);
  32. }
  33. inline void update(const dataType& rhs) {
  34. this->sumx += rhs.sumx, this->sumy += rhs.sumy;
  35. this->sqrs += rhs.sqrs, this->muls += rhs.muls;
  36. }
  37. };
  38. struct tagType {
  39. double S, T;
  40. inline tagType()
  41. : S(0.0), T(0.0) { }
  42. inline tagType(const double& s, const double& t)
  43. : S(s), T(t) { }
  44. inline bool operator == (const tagType& rhs) const {
  45. return (fabs(this->S - rhs.S) <= 1e-8) && (fabs(this->T - rhs.T) <= 1e-8);
  46. }
  47. inline bool operator != (const tagType& rhs) const {
  48. return !(*this == rhs);
  49. }
  50. };
  51. const tagType std_cov(-1e18, -1e18);
  52. const tagType std_add(0, 0);
  53. int L[S], R[S];
  54. dataType tr[S];
  55. tagType cov[S];
  56. tagType add[S];
  57. #define mid ((L[x] + R[x]) / 2)
  58. #define len double(R[x] - L[x] + 1)
  59. inline void pushup(int x) {
  60. tr[x] = tr[x << 1] + tr[x << 1 | 1];
  61. }
  62. inline void setCov(int x, const tagType& v) {
  63. double s1 = calculator::sum(L[x], R[x]);
  64. double s2 = calculator::sqrs(R[x]) - calculator::sqrs(L[x] - 1);
  65. tr[x].sqrs = s2 + len * v.S * v.S + 2 * v.S * s1;
  66. tr[x].muls = s2 + (v.S + v.T) * s1 + len * v.S * v.T;
  67. tr[x].sumx = s1 + len * v.S;
  68. tr[x].sumy = s1 + len * v.T;
  69. cov[x] = v, add[x] = std_add;
  70. }
  71. inline void setAdd(int x, const tagType& v) {
  72. tr[x].sqrs += v.S * v.S * len + 2 * v.S * tr[x].sumx;
  73. tr[x].muls += v.S * tr[x].sumy + v.T * tr[x].sumx + len * v.S * v.T;
  74. tr[x].sumx += v.S * len, tr[x].sumy += v.T * len;
  75. add[x].S += v.S, add[x].T += v.T;
  76. }
  77. inline void pushdown(int x) {
  78. if (cov[x] != std_cov) {
  79. setCov(x << 1, cov[x]);
  80. setCov(x << 1 | 1, cov[x]);
  81. cov[x] = std_cov;
  82. }
  83. if (add[x] != std_add) {
  84. setAdd(x << 1, add[x]);
  85. setAdd(x << 1 | 1, add[x]);
  86. add[x] = std_add;
  87. }
  88. }
  89. void build(int x, int l, int r, double* datx, double* daty) {
  90. L[x] = l, R[x] = r;
  91. cov[x] = std_cov, add[x] = std_add;
  92. if (l == r) {
  93. tr[x] = dataType(datx[l], daty[l]);
  94. return;
  95. }
  96. build(x << 1, l, mid, datx, daty);
  97. build(x << 1 | 1, mid + 1, r, datx, daty);
  98. pushup(x);
  99. }
  100. void modify(int x, int l, int r, void(*update)(int, const tagType&), const tagType& v) {
  101. if (l <= L[x] && R[x] <= r) return update(x, v);
  102. pushdown(x);
  103. if (l <= mid) modify(x << 1, l, r, update, v);
  104. if (r > mid) modify(x << 1 | 1, l, r, update, v);
  105. pushup(x);
  106. }
  107. void query(int x, int l, int r, dataType& ret) {
  108. if (l <= L[x] && R[x] <= r) return ret.update(tr[x]);
  109. if (l > R[x] || L[x] > r) return;
  110. pushdown(x), query(x << 1, l, r, ret), query(x << 1 | 1, l, r, ret);
  111. }
  112. #undef mid
  113. #undef len
  114. int n, Q;
  115. double x[N], y[N];
  116. signed main() {
  117. scanf("%d%d", &n, &Q);
  118. for (int i = 1; i <= n; i++) scanf("%lf", x + i);
  119. for (int i = 1; i <= n; i++) scanf("%lf", y + i);
  120. build(1, 1, n, x, y);
  121. while (Q--) {
  122. int opt, l, r;
  123. scanf("%d%d%d", &opt, &l, &r);
  124. if (opt == 1) {
  125. dataType res; query(1, l, r, res);
  126. double len = r - l + 1;
  127. double avex = res.sumx / len;
  128. double avey = res.sumy / len;
  129. double A = res.muls - res.sumx * res.sumy / len;
  130. double B = res.sqrs - res.sumx * res.sumx / len;
  131. printf("%lf\n", A / B);
  132. } else {
  133. tagType val; scanf("%lf%lf", &val.S, &val.T);
  134. modify(1, l, r, (opt == 2 ? setAdd : setCov), val);
  135. }
  136. }
  137. }

【SDOI2017】相关分析(线段树)的更多相关文章

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

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

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

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

  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】相关分析 [线段树]

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

  9. luogu3707 相关分析 (线段树)

    把式子展开以后会发现,可以用线段树维护$x,y,x*y,x^2$分别的区间和 然后操作有区间加和区间修改 这个pushdown的时候,如果改和加的标记同时存在,那一定是先改再加,要不然加的标记已经被清 ...

  10. LOJ #2005. 「SDOI2017」相关分析 线段树维护回归直线方程

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

随机推荐

  1. 单独编译一个ext4内核模块

    当我们需要使用一个内核模块的时候,在当前使用版本内核编译的时候又没有加进去,在不改变内核版本的时候,再编译整个内核,可能会覆盖原来的内核,导致系统无法启动 现在我们能够单独选择需要的模块,然后加载进内 ...

  2. Java POI导入word, 带图片

    1.导入文件示例,word中简历表格模板 2.代码示例分两部分,一部分读取图片 /** * 导入word(基本信息,word格式) * @param staffId * @param baseInfo ...

  3. 测试_QTP使用

    1.Qtp是什么? QTP是Quick Test Professional的简称,是一种自动测试工具.使用QTP的目的是想用它来执行重复的自动化测试,主要是用于回归测试和测试同一软件的新版本.(百度百 ...

  4. 04、MyBatis DynamicSQL(Mybatis动态SQL)

    1.动态SQL简介 动态 SQL是MyBatis强大特性之一. 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似. MyBatis 采用功能强大的基于 OGNL 的表达式来 ...

  5. HDU100题简要题解(2020~2029)

    HDU2020 绝对值排序 题目链接 Problem Description 输入n(n<=100)个整数,按照绝对值从大到小排序后输出.题目保证对于每一个测试实例,所有的数的绝对值都不相等. ...

  6. NO.A.0006——Git在IntelliJ IDEA中的使用/创建项目并推送到GitHub仓库/分支管理及分支合并

    一.在IntelliJ IDEA中使用Git: 1.在IDEA下创建项目并编写一个main方法的工程: 在IDEA下新建一个Project IDEA-->新建一个Project-->Fil ...

  7. 推荐一个适用于SpringBoot项目的轻量级HTTP客户端框架,快来试试它!

    在SpringBoot项目直接使用okhttp.httpClient或者RestTemplate发起HTTP请求,既繁琐又不方便统一管理.因此,在这里推荐一个适用于SpringBoot项目的轻量级HT ...

  8. 「CEOI2013」Board

    description 洛谷P5513 solution 用一个二进制数维护这个节点所处的位置,那么"1"操作就是这个数\(*2\),"2"操作就是这个数\(* ...

  9. 一 HTML基础入门

    HTML概念 HTML是标记语言,由W3C组织提供的一套标记标签组成.其使用标记标签来描述网页,一个网页除了由大量的标签组成,还有后续要学习的css样式和JavaScript脚本组合而成. 网页与网站 ...

  10. H5系列之canvas

    what is canvas?(什么是canvas) 其实他只是H5里面的一个标签而已,那么他作为一个标签,肯定有他的用途,他就像是一幅画布,等待着你来作画.可以说,他只是一个容器而已,需要配合着Ja ...