题目连接:
https://ac.nowcoder.com/acm/contest/26896/1015
分析:
掌握了步骤技巧感觉还是比较简单的,分析一下:
这个题感觉数学部分比较多…
-
要维护的信息有哪些?l,r,sum_sin,add(待补充)
-
如何维护?
(1)pushup时:这个简单嘛,区间和,随便搞
(2)懒标记,就一个,没啥好说的
(3)pushdown 和 打懒标记时 sum_sin信息的维护:
直接考虑实际例子:sum_sin = sin(a1) + sin(a2),区间+x
sum_sin’ = sin(a1 + x) + sin(a2 + x)
展开整理 = (sin(a1)+sin(a2))*cos(x) + (cos(a1)+cos(a2))*sin(x)
此时我们发现了还需要维护一个区间cos的和,因此补充上去sum_cos;
那么sum_sin’ = sum_sin * cos(x) + sum_cos * sin(x);那么加入sum_cos后要咋维护这个?
一样的套公式整理得:
sum_cos’ = sum_cos * cos(x) + sum_sin * sin(x); -
注意细节:
懒标记会爆int;
sum_sin’ = sum_sin * cos(x) + sum_cos * sin(x);
sum_cos’ = sum_cos * cos(x) + sum_sin * sin(x);
注意其中的sum_sin和sum_cos是更新前的,写的时候注意先存下来
代码
int n,m;
int a[maxn];
struct node
{
int l,r;
double sum_sin,sum_cos;
ll add;
}tr[maxn*4];
void pushup(int u)
{
tr[u].sum_sin = tr[u<<1].sum_sin + tr[u<<1|1].sum_sin;
tr[u].sum_cos = tr[u<<1].sum_cos + tr[u<<1|1].sum_cos;
}
void pushdown(int u)
{
if(tr[u].add)
{
ll x = tr[u].add;
double s_sin = tr[u<<1].sum_sin;
double s_cos = tr[u<<1].sum_cos;
tr[u<<1].sum_sin = s_sin*cos(x) + s_cos*sin(x);
tr[u<<1].sum_cos = s_cos*cos(x) - s_sin*sin(x);
tr[u<<1].add += x;
s_sin = tr[u<<1|1].sum_sin;
s_cos = tr[u<<1|1].sum_cos;
tr[u<<1|1].sum_sin = s_sin*cos(x) + s_cos*sin(x);
tr[u<<1|1].sum_cos = s_cos*cos(x) - s_sin*sin(x);
tr[u<<1|1].add += x;
tr[u].add = 0;
}
}
void build(int u,int l,int r)
{
if(l == r)
{
tr[u] = {l,r,sin(a[l]),cos(a[l]),0};
return;
}
tr[u] = {l,r};
int mid = l + r >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int x)
{
if(l > r) return;
if(tr[u].l >= l && tr[u].r <= r)
{
double s_sin = tr[u].sum_sin;
double s_cos = tr[u].sum_cos;
tr[u].sum_sin = s_sin*cos(x) + s_cos*sin(x);
tr[u].sum_cos = s_cos*cos(x) - s_sin*sin(x);
tr[u].add += x;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) update(u<<1, l, r, x);
if(r > mid) update(u<<1|1, l, r, x);
pushup(u); //向上更新
}
double query(int u,int l,int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum_sin;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
double ans = 0;
if(l <= mid) ans += query(u<<1, l, r);
if(r > mid) ans += query(u<<1|1, l, r);
return ans;
}
int main()
{
ire(n);
for(int i=1;i<=n;i++) ire(a[i]);
build(1,1,n);
ire(m);
while(m--)
{
int op;
ire(op);
if(op == 1)
{
int l,r,v;
iire(l,r); ire(v);
update(1,l,r,v);
}
else
{
int l,r;
iire(l,r);
double ans = query(1,l,r);
// cout<<ans<<"----"<<ans*10 - (int)(ans*10)<<endl;
if(fabs(ans*10 - (int)(ans*10)) >= 0.5) ans = (int)(ans*10) + (ans < 0 ? -1 : 1);
else ans = (int)(ans*10);
// cout<<ans<<endl;
ans /= 10;
printf("%.1lf\n",ans);
}
}
return 0;
}