P6327 区间加区间sin和 题解

题目描述

给出一个长度为 \(n\) 的整数序列 \(a_1,a_2,\ldots,a_n\),进行 \(m\) 次操作,操作分为两类。

操作 \(1\):给出 \(l,r,v\),将 \(a_l,a_{l+1},\ldots,a_r\) 分别加上 \(v\)。

操作 \(2\):给出 \(l,r\),询问 \(\sum\limits_{i=l}^{r}\sin(a_i)\)。

想法

考虑线段树。

对于一个节点 \([l, r]\) 它维护的应该是 \(\sin a_l + \sin a_{l + 1} +\dots+\sin a_r\)。

现在有两个问题摆在面前:

  1. up 操作
  2. down 操作

up

很明显,对于这道题而言,可以直接把左右儿子维护的 \(\sin\) 和加起来。

inline void up(int k)
{
tr[k].sin = tr[k << 1].sin + tr[k << 1 | 1].sin;
tr[k].cos = tr[k << 1].cos + tr[k << 1 | 1].cos;
}

down

和角公式:

\[\sin (\alpha +\beta) = \sin \alpha \cos \beta + \sin \beta \cos \alpha\\
\cos(\alpha + \beta) = \cos\alpha\cos\beta-\sin\alpha\sin\beta
\]

因而直接套公式,还需要另外维护 \(\cos\) 和。

inline void add(int k, double sinv, double cosv)
{
double sal = tr[k].sin, cal = tr[k].cos; // 注意要先备份一套sin和cos,调了好久Q^Q
tr[k].sin = sal * cosv + cal * sinv; // 更新区间sin和
tr[k].cos = cal * cosv - sal * sinv; // 更新区间cos和
} inline void down(int k)
{
int v = tr[k].tag;
double sinv = sin(v), cosv = cos(v);
add(k << 1, sinv, cosv);
add(k << 1 | 1, sinv, cosv);
tr[k << 1].tag += tr[k].tag, tr[k << 1 | 1].tag += tr[k].tag;
tr[k].tag = 0;
}

实现

剩下板

// Problem: P6327 区间加区间sin和
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P6327
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Moyou
// Copyright (c) 2022 Moyou All rights reserved.
// Date: 2023-01-31 15:25:03 #include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <tuple>
#include <unordered_map>
#define x first
#define y second
#define speedup (ios::sync_with_stdio(0), cin.tie(0), cout.tie(0))
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
typedef long long LL;
typedef pair<int, int> PII; const int N = 2e5 + 10; int n, m;
int a[N]; inline char get_char()
{
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
} inline int read()
{
int x = 0;
char ch = get_char();
while (ch < '0' || ch > '9')
ch = get_char();
while (ch <= '9' && ch >= '0')
x = (x << 1) + (x << 3) + (ch ^ 48), ch = get_char();
return x;
} double sinv, cosv; struct owo
{
int l, r;
double sin, cos;
int tag;
} tr[N << 2]; inline void up(int k)
{
tr[k].sin = tr[k << 1].sin + tr[k << 1 | 1].sin;
tr[k].cos = tr[k << 1].cos + tr[k << 1 | 1].cos;
} inline void add(int k, double sinv, double cosv)
{
double sal = tr[k].sin, cal = tr[k].cos; // 注意要先备份一套sin和cos,调了好久Q^Q
tr[k].sin = sal * cosv + cal * sinv; // 更新区间sin和
tr[k].cos = cal * cosv - sal * sinv; // 更新区间cos和
} inline void down(int k)
{
int v = tr[k].tag;
double sinv = sin(v), cosv = cos(v);
add(k << 1, sinv, cosv);
add(k << 1 | 1, sinv, cosv);
tr[k << 1].tag += tr[k].tag, tr[k << 1 | 1].tag += tr[k].tag;
tr[k].tag = 0;
} void build(int k, int l, int r)
{
tr[k] = {l, r, 0, 0};
if (l == r)
tr[k] = {l, r, sin(a[l]), cos(a[l]), 0};
else
{
int mid = l + r >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
up(k);
}
} void update(int k, int ql, int qr, int v)
{
int l = tr[k].l, r = tr[k].r, mid = l + r >> 1;
if (ql <= l && qr >= r) // 查询区间包含当前区间
{
add(k, sinv, cosv); // 更新
tr[k].tag += v; // 打懒标记
return;
}
if (tr[k].tag)
down(k);
if(ql <= mid) update(k << 1, ql, qr, v);
if(qr > mid) update(k << 1 | 1, ql, qr, v);
up(k);
} double query(int k, int ql, int qr)
{
int l = tr[k].l, r = tr[k].r, mid = l + r >> 1;
if(ql <= l && qr >= r)
return tr[k].sin;
if(tr[k].tag) down(k);
double tmp = 0;
if(ql <= mid) tmp += query(k << 1, ql, qr);
if(qr > mid) tmp += query(k << 1 | 1, ql, qr);
return tmp;
} signed main()
{
n = read();
for (int i = 1; i <= n; i++)
a[i] = read();
m = read();
build(1, 1, n);
while (m--)
{
int op = read(), l = read(), r = read();
if (--op)
printf("%.1lf\n", query(1, l, r));
else
{
int v = read();
sinv = sin(v), cosv = cos(v);
update(1, l, r, v);
}
}
return 0;
}

P6327 区间加区间sin和 题解的更多相关文章

  1. [用CDQ分治解决区间加&区间求和]【习作】

    [前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Par ...

  2. 「模板」 线段树——区间乘 && 区间加 && 区间求和

    「模板」 线段树--区间乘 && 区间加 && 区间求和 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long l ...

  3. 【BZOJ】1798: [Ahoi2009]Seq 维护序列seq 线段树多标记(区间加+区间乘)

    [题意]给定序列,支持区间加和区间乘,查询区间和取模.n<=10^5. [算法]线段树 [题解]线段树多重标记要考虑标记与标记之间的相互影响. 对于sum*b+a,+c直接加上即可. *c后就是 ...

  4. P4315 月下“毛景树” (树链剖分+边剖分+区间覆盖+区间加+区间最大值)

    题目链接:https://www.luogu.org/problem/P4315 题目大意: 有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力 ...

  5. COGS.1317.数列操作c(分块 区间加 区间求和)

    题目链接 #include<cmath> #include<cstdio> #include<cctype> #include<algorithm> u ...

  6. poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和

    A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...

  7. poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和(模板)

    A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...

  8. LOJ6283 数列分块入门 7 (分块 区间加/乘)题解

    题意:区间加,区间乘,单点询问 思路:假设一个点为a,那么他可以表示为m * a + sum,所以区间加就变为m * a + sum + sum2,区间乘变为m * m2 * a + sum * m2 ...

  9. HDU 5828 Rikka with Sequence(线段树区间加开根求和)

    Problem DescriptionAs we know, Rikka is poor at math. Yuta is worrying about this situation, so he g ...

  10. 区间加值,区间gcd, 牛客949H

    牛客小白月赛16H 小阳的贝壳 题目链接 题意 维护一个数组,支持以下操作: 1: 区间加值 2: 询问区间相邻数差的绝对值的最大值 3: 询问区间gcd 题解 设原数组为\(a\), 用线段树维护\ ...

随机推荐

  1. 更改DataFrame列顺序

    使用pandas进行数据分析的时候,有时会由于各种需求添加了一些列.可是列的顺序并不能符合自己的期望.这个时候就需要对于列的顺序进行调整. import numpy as np import pand ...

  2. SpringBoot问题集合

    Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as ...

  3. 系统整理K8S的配置管理实战-建议收藏系列

    目录 一.ConfigMap 1.1.创建 1.1.1.from-file 1.1.2.from-env-file 1.1.3.from-literal 1.1.4.基于yaml文件创建 1.2.Po ...

  4. 重新整理 .net core 实践篇 ———— dotnet-dump [外篇]

    前言 本文的上一篇为: https://www.cnblogs.com/aoximin/p/16861797.html 该文为dotnet-dump 和 procdump 的实战介绍一下. 正文 现在 ...

  5. UWSGI 安装出现 ModuleNotFoundError: No module named '_ctypes'

    原因:Python3中有个内置模块叫ctypes,它是Python3的外部函数库模块,它提供兼容C语言的数据类型,并通过它调用Linux系统下的共享库(Shared library),此模块需要使用C ...

  6. 关于CSDN获取博客内容接口的x-ca-signature签名算法研究

    前言 源码下载 不知道怎么就不通过了,这篇文章放出去几个月了,然后突然告诉我不行了,所以我打算换个平台(至少不能在一棵树吊死),垃圾审核 我最初想直接获取html博客,然后保存在本地,最后发布到别的博 ...

  7. 第二十五节:scrapy爬虫识别验证码(四)手绘验证码识别

    一.介绍 今天主要介绍的是微博客户端在登录时出现的四宫格手绘验证码,不多说直接看看验证码长成什么样.        二.思路 1.由于微博上的手绘验证码只有四个宫格,且每个宫格之间都有有向线段连接,所 ...

  8. 4.3:flume+Kafka日志采集实验

    〇.目标 使用kafka和flume组合进行日志采集 拓扑结构 一.重启SSH和zk服务 打开终端,首先输入:sudo service ssh restart 重启ssh服务.之后输入下述命令开启zo ...

  9. eval解析的函数传参 object array

    1 const fn = (...args) => { 2 console.log(...args) 3 } 4 5 const handleEval = (fnName,...args) =& ...

  10. 玩 ChatGPT 的正确姿势「GitHub 热点速览 v.22.49」

    火了一周的 ChatGPT,HG 不允许还有小伙伴不知道这个东西是什么?简单来说就是,你可以让它扮演任何事物,据说已经有人用它开始了颜色文学创作.因为它太火了,所以,本周特推在几十个带有"c ...