复制代码

线段树

线段树

区间加 区间和

区间乘法的懒标记优先级高于加法,且会对加法懒标记造成影响

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)\)

gcd区间

#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;
}

P4588

区间不同数的个数

\(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;
}

区间 加,乘后询问区间和

1008

#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;
}
posted @ 2024-08-28 21:32  Elgina  阅读(20)  评论(5)    收藏  举报