线段树
线段树
区间加 区间和
区间乘法的懒标记优先级高于加法,且会对加法懒标记造成影响
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum; //
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void push_down(vector<node> &tr,int u) { //
if(tr[u].la != 0) {
tr[u<<1].la += tr[u].la;
tr[u<<1|1].la += tr[u].la;
tr[u<<1].sum += (tr[u<<1].r - tr[u<<1].l + 1) * 1ll * tr[u].la;
tr[u<<1|1].sum += (tr[u<<1|1].r - tr[u<<1|1].l + 1) * 1ll * tr[u].la;
tr[u].la = 0;
}
}
void build(vector<node> &tr, int u, int l, int r,vector<int> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l],0}; //
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, int k) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) { // 目标区间
tr[u].sum += 1ll * (r - l + 1) * k;
tr[u].la += k;
return;
}
int mid = (l + r) >> 1;
push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k);
if(R > mid) modify(tr,u<<1|1,L,R,k);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
区间赋值 等差数列
\(1\ l\ r\ k\) :表示将下标在 \([l , r]\) 区间内的数字替换成 \([k,k+1,…,k+r-l]\)
\(lazy\) 仅表示一个区间最左侧的值 ,通过\(lazy\) 和区间长度 可以得到 \(sum\)
$sum = (lazy + lazy + (len - 1)) / 2 * len $
$sum = \frac{n(a_{1} + a_{n})}{2} $
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
struct node{
int l,r;
ll sum;
ll la;
};
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum;
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void push_down(vector<node> &tr,int u) {
if(tr[u].la != 0) {
ll len = tr[u<<1].r - tr[u<<1].l + 1;
tr[u<<1].la = tr[u].la;
tr[u<<1].sum = (tr[u].la + tr[u].la + len - 1) * len / 2;
tr[u<<1|1].la = tr[u].la + len;
ll lgt = tr[u<<1|1].r - tr[u<<1|1].l + 1;
tr[u<<1|1].sum = (tr[u<<1|1].la + tr[u<<1|1].la + lgt - 1) * lgt / 2;
tr[u].la = 0;
}
}
void build(vector<node> &tr, int u, int l, int r,vector<int> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l],0};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, int k) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) { // 目标区间 L,R
tr[u].la = k + (l - L);
tr[u].sum = (tr[u].la + tr[u].la + (r - l) ) * (r - l + 1) / 2;
return;
}
int mid = (l + r) >> 1;
push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k);
if(R > mid) modify(tr,u<<1|1,L,R,k);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,q;
std::cin >> n >> q;
std::vector<int> a(n+1);
std::vector<node> tr(n * 4 + 4);
for(int i = 1; i <= n; i++) std::cin >> a[i];
build(tr,1,1,n,a);
while(q --) {
int op,x,y,k;
std::cin >> op;
if(op == 1) {
std::cin >> x >> y >> k;
modify(tr,1,x,y,k);
}
else {
std::cin >> x >> y;
std::cout << query(tr,1,x,y).sum << '\n';
}
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
区间gcd
给定一个长度为N的数列A,以及M条指令 (N≤5*10^5, M<=10^5),每条指令可能是以下两种之一:
“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
首先区间\(gcd\) 具有合并性 \(u.d = gcd(l.d,r.d)\)
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll gcd(ll a,ll b) {
return b == 0 ? a : gcd(b,a%b);
}
struct node{
int l,r;
ll d;
};
void push_up(node &u,node &l,node &r) {
u.d = gcd(l.d,r.d);
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(vector<node> &tr, int u, int l, int r,vector<int> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l]};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,q;
std::cin >> n >> q;
std::vector<int> a(n+1);
std::vector<node> tr(n * 4 + 4);
for(int i = 1; i <= n; i++) std::cin >> a[i];
build(tr,1,1,n,a);
while(q --) {
int x,y;
std::cin >> x >> y;
std::cout << query(tr,1,x,y).d << '\n';
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
但是\(gcd(a_l+v,a_{l+1}+v,...,a_r + v)\) 与 \(gcd(a_l,a_{l+1},...,a_r)\) 无关,

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll gcd(ll a,ll b) {
return b == 0 ? a : gcd(b,a%b);
}
struct node{
ll l,r;
ll sum;
ll d;
};
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum;
u.d = gcd(l.d,r.d);
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(vector<node> &tr, int u, int l, int r,vector<ll> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l],a[l]};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, ll k) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) { // 目标区间
tr[u].sum += k;
tr[u].d += k;
return;
}
int mid = (l + r) >> 1;
//push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k);
if(R > mid) modify(tr,u<<1|1,L,R,k);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
//push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,q;
std::cin >> n >> q;
std::vector<ll> a(n+1),b(n+1);
std::vector<node> tr(n * 3);
for(int i = 1; i <= n; i++) std::cin >> a[i];
for(int i = 1; i <= n; i++) {
b[i] = a[i] - a[i-1];
}
build(tr,1,1,n,b);
while(q --) {
char op;
int x,y; ll k;
std::cin >> op;
if(op == 'C') {
std::cin >> x >> y >> k;
modify(tr,1,x,x,k);
if(y + 1 <= n) {
modify(tr,1,y+1,y+1,-k);
}
}
else {
std::cin >> x >> y;
ll A1 = 0 , A2 = 0;
if(x <= n) A1 = query(tr,1,1,x).sum;
if(x + 1 <= y) A2 = query(tr,1,x+1,y).d;
std::cout << std::abs( gcd(A1,A2) ) << '\n';
}
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
区间最大连续子段和
\(max_{x \leq l \leq r \leq y}({\sum_{r_i=l}^{r}A[i]})\)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
struct node{
int l,r;
int sum;
int lmx,rmx,mx;
};
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum;
u.lmx = max(l.lmx, l.sum + r.lmx);
u.rmx = max(r.rmx, r.sum + l.rmx);
u.mx = max({l.mx,r.mx,l.rmx + r.lmx});
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(vector<node> &tr, int u, int l, int r,vector<int> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l],a[l],a[l],a[l]};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, int k) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) { // 目标区间
tr[u].sum = k;
tr[u].lmx = k;
tr[u].rmx = k;
tr[u].mx = k;
return;
}
int mid = (l + r) >> 1;
//push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k);
if(R > mid) modify(tr,u<<1|1,L,R,k);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
//push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,q;
std::cin >> n >> q;
std::vector<int> a(n+1);
std::vector<node> tr(n * 4 + 4);
for(int i = 1; i <= n; i++) std::cin >> a[i];
build(tr,1,1,n,a);
while(q --) {
int op,x,y; int k;
std::cin >> op;
if(op == 1) {
std::cin >> x >> y;
if(x > y) swap(x,y);
std::cout << query(tr,1,x,y).mx << '\n';
}
else {
std::cin >> x >> k;
modify(tr,1,x,x,k);
}
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
区间不同数的个数
将\(l == r\) 的线段树赋值为1, 区间不同数的个数就表示为区间和
考虑如何去重;
由于离线询问,将询问的 \(r\),记录下来并排好序,枚举 \(r\) 的范围 $1 \le r \le n $
现在我们询问的肯定是 \(r\)为终点,左边的一段。对答案有贡献的只有距离\(r\)最近的
考虑用\(last\) 来标记当前位置数上次出现的位置, 如果有说明在这个区间 至少\(\ge2\)个这个数 把上一次的位置 \(modify\) 为 0 就好 ,同时更新 \(last\)
利用\(id\) 不以询问顺序存入答案数组,最后统一输出即可。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e6 + 4;
struct node{
int l,r;
int sum;
};
struct mode{
int l,r;
int id;
}t[N];
int ans[N];
bool cmp(mode a,mode b) {
if(a.r == b.r) return a.l < b.l;
return a.r < b.r;
}
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum; //
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(vector<node> &tr, int u, int l, int r,vector<int> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l]}; //
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, int k) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) { // 目标区间
tr[u].sum = k;
return;
}
int mid = (l + r) >> 1;
//push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k);
if(R > mid) modify(tr,u<<1|1,L,R,k);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
//push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n+1),b(n+1,1);
std::vector<node> tr(n * 4 + 4);
build(tr,1,1,n,b);
for(int i = 1; i <= n; i++) std::cin >> a[i];
int q;
std::cin >> q;
for(int i = 1; i <= q; i++) {
std::cin >> t[i].l >> t[i].r;
t[i].id = i;
}
std::sort(t+1,t+q+1,cmp);
std::vector< vector<int> > v(n+1);
for(int i = 1; i <= q; i++) {
v[t[i].r].push_back(i);
}
std::map<int,int> last;
for(int i = 1; i <= n; i++) {
if(last[a[i]] > 0) modify(tr,1,last[a[i]],last[a[i]],0);
last[a[i]] = i;
for(auto u : v[i]) {
//std::cout << u << '\n';
ans[t[u].id] = query(tr,1,t[u].l,t[u].r).sum;
}
}
for(int i = 1; i <= q; i++) {
std::cout << ans[i] << '\n';
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
区间 加,乘后询问区间和
#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int N = 2e3 + 4;
const ll mod = 1e9 + 7;
struct node{
ll l,r;
ll add,mul,sum,res;
};
void eval(node &u,ll add,ll mul) {//
u.res = (u.res * mul * mul + 2 * u.sum * mul * add + (u.r - u.l + 1) * add * add);
u.sum = u.sum * mul + (u.r - u.l + 1) * add;
u.mul = u.mul * mul;
u.add = u.add * mul + add;
}
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum;
u.res = l.res + r.res;
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void push_down(vector<node> &tr,int u) { //
eval(tr[u<<1],tr[u].add,tr[u].mul);
eval(tr[u<<1|1],tr[u].add,tr[u].mul);
tr[u].add = 0;
tr[u].mul = 1;
}
void build(vector<node> &tr, int u, int l, int r,vector<ll> &a) {
tr[u].l = l; tr[u].r = r; tr[u].add = 0; tr[u].mul = 1;
if (l == r) {
tr[u] = {l,r,0,1,a[l],a[l]*a[l]};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, int k,int x) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) { // 目标区间
eval(tr[u],k,x); // +k *x
return;
}
int mid = (l + r) >> 1;
push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k,x);
if(R > mid) modify(tr,u<<1|1,L,R,k,x);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,m;
std::cin >> n >> m;
std::vector<ll> a(n+1);
std::vector<node> tr(n*4+4);
for(int i = 1; i <= n; i++) {
std::cin >> a[i];
}
build(tr,1,1,n,a);
while(m --) {
int op,l,r,x;
std::cin >> op;
if(op == 1) {
std::cin >> l >> r;
std::cout << query(tr,1,l,r).sum << '\n';
}
else if(op == 2) {
std::cin >> l >> r;
std::cout << query(tr,1,l,r).res << '\n';
}
else if(op == 3) {
std::cin >> l >> r >> x;
modify(tr,1,l,r,0,x);
}
else {
std::cin >> l >> r >> x;
modify(tr,1,l,r,x,1);
}
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
区间修改:开方
一个\(1e18\)以内的数,开最多6次就是1,也就是说,每一个叶子节点最多只会被更新六次,所以我们用线段树维护区间最大值和区间和,对于区间最大值为1的区间就不再做任何开方操作。
#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
const int N = 2e3 + 4;
const ll mod = 1e9 + 7;
using namespace std;
struct node{
int l,r;
ll sum,mx;
};
void push_up(node &u,node &l,node &r) {
u.sum = l.sum + r.sum;
u.mx = max(l.mx,r.mx);
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
/*void push_down(vector<node> &tr,int u) { //
if(tr[u].la != 0) {
tr[u<<1].la += tr[u].la;
tr[u<<1|1].la += tr[u].la;
tr[u<<1].sum += (tr[u<<1].r - tr[u<<1].l + 1) * 1ll * tr[u].la;
tr[u<<1|1].sum += (tr[u<<1|1].r - tr[u<<1|1].l + 1) * 1ll * tr[u].la;
tr[u].la = 0;
}
}*/
void build(vector<node> &tr, int u, int l, int r,vector<ll> &a) {
tr[u].l = l; tr[u].r = r;
if (l == r) {
tr[u] = {l,r,a[l],a[l]};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R) {
int l = tr[u].l, r = tr[u].r;
if(l == r) {
tr[u].sum = sqrt(tr[u].sum);
tr[u].mx = sqrt(tr[u].mx);
return;//要及时退出
}
if(tr[u].mx == 1) return;
int mid = (l + r) >> 1;
//push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R);
if(R > mid) modify(tr,u<<1|1,L,R);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
//push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,m;
std::cin >> n >> m;
std::vector<ll> a(n+1);
std::vector<node> tr(n * 4 + 4);
for(int i = 1; i <= n; i++) {
std::cin >> a[i];
}
build(tr,1,1,n,a);
while(m --) {
int op,l,r;
std::cin >> op >> l >> r;
if(op == 1) {
modify(tr,1,l,r);
}
else {
std::cout << query(tr,1,l,r).sum << '\n';
}
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}
区间加 区间sin和 cos和
\(sin(x+v) = sin(x) * cos(v) + cos(x) * sin(v)\)
\(cos(x + v) = cos(x) * cos(v) - sin(x) * sin(v)\)
先算出每个区间的\(sin,cos\) 可以推算出区间加\(v\)后的区间\(sin\)和
区间加需要用到懒标记
#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double dl;
using namespace std;
const int N = 2e3 + 4;
const ll mod = 1e9 + 7;
struct node{
int l,r;
dl la;
dl Sin,Cos;
};
void push_up(node &u,node &l,node &r) {
u.Sin = l.Sin + r.Sin;
u.Cos = l.Cos + r.Cos;
}
void pushup(vector<node> &tr, int u) {
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void eval(node &u,dl si, dl co) {
dl sinx = u.Sin, cosx = u.Cos;
u.Sin = sinx * co + cosx * si;
u.Cos = cosx * co - sinx * si;
}
void push_down(vector<node> &tr,int u) { //
if(tr[u].la != 0) {
eval(tr[u<<1],sin(tr[u].la),cos(tr[u].la));
eval(tr[u<<1|1],sin(tr[u].la),cos(tr[u].la));
tr[u<<1].la += tr[u].la;
tr[u<<1|1].la += tr[u].la;
tr[u].la = 0;
}
}
void build(vector<node> &tr, int u, int l, int r,vector<dl> &a) {
tr[u].l = l; tr[u].r = r; tr[u].la = 0;
if (l == r) {
tr[u] = {l,r,0,sin(a[l]),cos(a[l])};
return;
}
int mid = (l + r) >> 1;
build(tr,u << 1,l,mid,a);
build(tr,u << 1 | 1,mid + 1,r,a);
pushup(tr, u);
}
void modify(vector<node> &tr, int u , int L , int R, dl k) {
int l = tr[u].l, r = tr[u].r;
if(l >= L && r <= R) {
eval(tr[u],sin(k),cos(k));
tr[u].la += k;
return;
}
int mid = (l + r) >> 1;
push_down(tr,u);
if(L <= mid) modify(tr,u<<1,L,R,k);
if(R > mid) modify(tr,u<<1|1,L,R,k);
pushup(tr,u);
}
node query(vector<node> &tr,int u,int L,int R) {
if(L <= tr[u].l && tr[u].r <= R) return tr[u];
int mid = (tr[u].l + tr[u].r) >> 1;
push_down(tr,u);
if(R <= mid) return query(tr,u << 1,L,R);
else if(L > mid) return query(tr,u << 1 | 1,L,R);
else {
node p,pl,pr;
pl = query(tr,u << 1,L,R);
pr = query(tr,u << 1 | 1,L,R);
push_up(p,pl,pr);
return p;
}
}
void solve() {
int n,m;
std::cin >> n;
std::vector<dl> a(n+1);
for(int i = 1; i <= n; i++) {
std::cin >> a[i];
}
std::cin >> m;
std::vector<node> tr(n*4+4);
build(tr,1,1,n,a);
while(m --) {
int op,l,r; dl x;
std::cin >> op;
if(op == 1) {
std::cin >> l >> r >> x;
modify(tr,1,l,r,x);
}
else {
std::cin >> l >> r;
std::cout << std::fixed << std::setprecision(1) << query(tr,1,l,r).Sin << '\n';
}
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int _ = 1;
//std::cin >> _;
while(_ --) {
solve();
}
return 0;
}

浙公网安备 33010602011771号