1. 程式人生 > >帶 sin, cos 的線段樹 - 牛客

帶 sin, cos 的線段樹 - 牛客

int ace 思路分析 長度 一個 答案 四舍五入 ret def

鏈接:https://www.nowcoder.com/acm/contest/160/D
來源:牛客網

題目描述
給出一個長度為n的整數序列a1,a2,...,an,進行m次操作,操作分為兩類。
操作1:給出l,r,v,將al,al+1,...,ar分別加上v;
操作2:給出l,r,詢問
輸入描述:

第一行一個整數n
接下來一行n個整數表示a1,a2,...,an
接下來一行一個整數m
接下來m行,每行表示一個操作,操作1表示為1 l r v,操作2表示為2 l r
保證1≤n,m,ai,v≤200000;1≤l≤r≤n,v是整數

輸出描述:

對每個操作2,輸出一行,表示答案,四舍五入保留一位小數
保證答案的絕對值大於0.1,且答案的準確值的小數點後第二位不是4或5
數據隨機生成(n,m人工指定,其余整數在數據範圍內均勻選取),並去除不滿足條件的操作2

輸入

4
1 2 3 4
5
2 2 4
1 1 3 1
2 2 4
1 2 4 2
2 1 3

輸出

0.3
-1.4
-0.3

題意 : 給你 n 個數字,第一種操作是將一個區間內每一個數字加上同一個數字,第二種操作是求一個區間內每一個數 sin 的累加和

思路分析 :對於每個區間維護一下 cos 和 sin 的值,當一個區間要加上一個數字時,此時再重新計算 sin的值時 , sin(a + x) = sin(a)*cos(x) + cos(a)*sin(x) ,一個區間內的所有值都可以這樣計算,因此就會用到區間內的 sin 總和 以及 cos 的總和

這個題有個很坑的地方,就是大量的地方用到 sin 與 cos 函數,若輸入的是一個整形數強制轉變為浮點數後再用 sin函數,cos函數則會超時,不強制轉換會快一半的時間!!!

代碼示例 :

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5+5;
#define lson k<<1
#define rson k<<1|1

int n, m;
struct node
{
	int l, r;
	ll lazy;
	double rs, rc;
}t[maxn<<2];

void pushdown(int k){
	double x1 = t[lson].rs*cos(t[k].lazy) + t[lson].rc*sin(t[k].lazy);
	double x2 = t[lson].rc*cos(t[k].lazy) - t[lson].rs*sin(t[k].lazy);
	t[lson].rs = x1, t[lson].rc = x2;
	
	x1 = t[rson].rs*cos(t[k].lazy) + t[rson].rc*sin(t[k].lazy);
	x2 = t[rson].rc*cos(t[k].lazy) - t[rson].rs*sin(t[k].lazy);
	t[rson].rs = x1, t[rson].rc = x2;
	
	t[lson].lazy += t[k].lazy;
	t[rson].lazy += t[k].lazy;
	t[k].lazy = 0;
}
int x;
void build(int l, int r, int k){
	t[k].l = l, t[k].r = r;
	t[k].rc = t[k].rs = 0.0;
	t[k].lazy = 0;
	if (l == r) {
		scanf("%d", &x);
		t[k].rs = sin(x), t[k].rc = cos(x);
		return;
	}
	int m = (l+r) >> 1;
	build(l, m, lson);
	build(m+1, r, rson);
	
	t[k].rs = t[lson].rs+t[rson].rs;
	t[k].rc = t[lson].rc+t[rson].rc;
}

void update(int l, int r, ll v, int k){
	if (l <= t[k].l && t[k].r <= r){
		double x1 = t[k].rs*cos(v)+t[k].rc*sin(v);
		double x2 = t[k].rc*cos(v)-t[k].rs*sin(v);
		t[k].rs = x1, t[k].rc = x2;
		t[k].lazy += v;
		return;
	}
	if (t[k].lazy) pushdown(k);
	int m = (t[k].l+t[k].r) >> 1;
	if (l <= m) update(l, r, v, lson);
	if (r > m) update(l, r, v, rson);
	t[k].rs = t[lson].rs+t[rson].rs;
	t[k].rc = t[lson].rc+t[rson].rc;
}

double sum;
void query(int l, int r, int k){
	if (l <= t[k].l && t[k].r <= r){
		sum += t[k].rs;
		return;
	}
	if (t[k].lazy) pushdown(k);
	int m = (t[k].l + t[k].r) >> 1;
	if (l <= m) query(l, r, lson);
	if (r > m) query(l, r, rson);
}

int main() {
	int pt, l, r;
	ll v;
	
	cin >> n;
	build(1, n, 1);
	cin >> m;
	while(m--){
		scanf("%d%d%d", &pt, &l, &r);
		if (pt == 1) {
			scanf("%lld", &v);
			update(l, r, v, 1);
		}	
		else {
			sum = 0;
			query(l, r, 1);
			printf("%.1lf\n", sum);
		}
	}
	return 0;
}

帶 sin, cos 的線段樹 - 牛客