Wannafly挑战赛22-D:整数序列(线段树)

链接:https://www.nowcoder.com/acm/contest/160/D

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给出一个长度为 n 的整数序列 a 1 , a 2 , . . . , a n ,进行 m 次操作,操作分为两类。
操作1:给出 l , r , v ,将 a l , a l + 1 , . . . , a r 分别加上 v
操作2:给出 l , r ,询问 i = l r s i n ( a i )
输入描述:
第一行一个整数 n
接下来一行 n 个整数表示 a 1 , a 2 , . . . , a n
接下来一行一个整数 m
接下来 m 行,每行表示一个操作,操作1表示为 1 l r v ,操作2表示为 2 l r
保证 1 n , m , a i , v 200000 1 l r n v 是整数
输出描述:
对每个操作2,输出一行,表示答案,四舍五入保留一位小数
保证答案的绝对值大于0.1,且答案的准确值的小数点后第二位不是4或5
数据随机生成(n,m人工指定,其余整数在数据范围内均匀选取),并去除不满足条件的操作2
示例1
输入
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
思路:利用公式

s i n ( a + b ) = s i n ( a ) c o s ( b ) + c o s ( a ) s i n ( b )
c o s ( a + b ) = c o s ( a ) c o s ( b ) s i n ( a ) s i n ( b )
于是我们可以维护区间内 s i n ( a i ) c o s ( a i ) .
然后更新操作的话,可以用懒惰标记,并利用上面2个公式更新答案

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
const int MAX=2e5+10;
const double PI=acos(-1.0);
typedef long long ll;
int a[MAX];
struct lenka
{
    int l,r;
    ll tag;
    double sinum,cosum;
}A[MAX<<2];
void build(int k,int l,int r)
{
    A[k].l=l,A[k].r=r;
    A[k].tag=0;
    if(l==r)
    {
        A[k].sinum=sin(1.0*a[r]);
        A[k].cosum=cos(1.0*a[r]);
        return;
    }
    build(2*k,l,(l+r)/2);
    build(2*k+1,(l+r)/2+1,r);
    A[k].sinum=A[2*k].sinum+A[2*k+1].sinum;
    A[k].cosum=A[2*k].cosum+A[2*k+1].cosum;
}
void add(int k,int x,int y,ll z)
{
    if(x==A[k].l&&y==A[k].r)
    {
        double C=cos(z);
        double S=sin(z);
        double SIN=A[k].sinum*C+A[k].cosum*S;
        double COS=A[k].cosum*C-A[k].sinum*S;
        A[k].sinum=SIN;
        A[k].cosum=COS;
        if(x!=y)A[k].tag+=z;
        return;
    }
    if(A[k].tag)
    {
        add(2*k,A[2*k].l,A[2*k].r,A[k].tag);
        add(2*k+1,A[2*k+1].l,A[2*k+1].r,A[k].tag);
        A[k].tag=0;
    }
    if(y<=A[2*k].r)add(2*k,x,y,z);
    else if(x>=A[2*k+1].l)add(2*k+1,x,y,z);
    else
    {
        add(2*k,x,A[2*k].r,z);
        add(2*k+1,A[2*k+1].l,y,z);
    }
    A[k].sinum=A[2*k].sinum+A[2*k+1].sinum;
    A[k].cosum=A[2*k].cosum+A[2*k+1].cosum;
}
double ask(int k,int x,int y)
{
    if(x==A[k].l&&y==A[k].r)return A[k].sinum;
    if(A[k].tag)
    {
        add(2*k,A[2*k].l,A[2*k].r,A[k].tag);
        add(2*k+1,A[2*k+1].l,A[2*k+1].r,A[k].tag);
        A[k].tag=0;
    }
    double sum=0;
    if(y<=A[2*k].r)sum=ask(2*k,x,y);
    else if(x>=A[2*k+1].l)sum=ask(2*k+1,x,y);
    else  sum=ask(2*k,x,A[2*k].r)+ask(2*k+1,A[2*k+1].l,y);
    return sum;
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    build(1,1,n);
    int m;
    cin>>m;
    while(m--)
    {
        int op,x,y;
        ll z;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)
        {
            scanf("%lld",&z);
            add(1,x,y,z);
        }
        else printf("%.1f\n",ask(1,x,y));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81812690
今日推荐