Wannafly 挑战赛22 D 整数序列 线段树 区间更新,区间查询

Posted draymonder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wannafly 挑战赛22 D 整数序列 线段树 区间更新,区间查询相关的知识,希望对你有一定的参考价值。

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

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

给出一个长度为n的整数序列a1,a2,...,an,进行m次操作,操作分为两类。
操作1:给出l,r,v,将al,al+1,...,ar分别加上v;
操作2:给出l,r,询问技术分享图片

输入描述:

n个数,m次操作
op=1, l,r,v 区间[l,r] 加v
op=2, l,r 区间查询上式
n,m,val[i] <= 2e5

输出描述:

对每个操作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

很明显区间更新的题 用lazy维护某一段区间的 sin(val[i])和 cos(val[i])值
根据下面的式子 可知道 要保证区间加和性,就要先要 维护sin(x) 区间加和的性质
so 看代码 和 公式 应该差不多能理解的
// sin(x + v) = sinx*cosv+sinvcosx
// cos(x + v) = cosx*cosv-sinx*sinv

// sin(x1 + v) + sin(x2 + v) = cosv*(sinx1+sinx2) + sinv*(cosx1+cosx2)
// cos(x1 + v) + cos(x1 + v) = cosv*(cosx1+cosx2) - sinv*(sinx1+sinx2)
#include<bits/stdc++.h>
using namespace std;

const int N = 200000+10;
#define ls rt<<1
#define rs rt<<1|1
typedef long long ll;

ll val[N], lz[N<<3];
double ssin[N<<3],ccos[N<<3];

void up(int rt) {
    ssin[rt] = ssin[ls] + ssin[rs];
    ccos[rt] = ccos[ls] + ccos[rs];
}

void down(int rt) {
    if(lz[rt]) {
        ll v = lz[rt];
        lz[ls] += v;
        lz[rs] += v;

        double tsin=ssin[ls], tcos=ccos[ls];
        ssin[ls]=tsin*cos(v) + tcos*sin(v);
        ccos[ls]=tcos*cos(v) - tsin*sin(v);

        tsin=ssin[rs],tcos=ccos[rs];
        ssin[rs]=tsin*cos(v) + tcos*sin(v);
        ccos[rs]=tcos*cos(v) - tsin*sin(v);
        lz[rt]=0;
    }
}

void build(int rt,int l,int r) {
    if(l==r) {
        ssin[rt]=sin(val[l]);
        ccos[rt]=cos(val[l]);
        return ;
    }
    int m = (l+r)/2;
    build(ls,l,m);
    build(rs,m+1,r);
    up(rt);
}

void update(int rt,int l,int r,int L,int R,ll v) {
    if(L <= l && r <= R) {
        lz[rt] += v;
        double tsin=ssin[rt], tcos=ccos[rt];
        ssin[rt]=tsin*cos(v) + tcos*sin(v);
        ccos[rt]=tcos*cos(v) - tsin*sin(v);
        return ;
    }
    down(rt);
    int m = (l+r)/2;
    if(L <= m)
        update(ls,l,m,L,R,v);
    if(m < R)
        update(rs,m+1,r,L,R,v);
    up(rt);
}

double query(int rt,int l,int r,int L,int R) {
    if(L<=l && r<=R) {
        return ssin[rt];
    }
    down(rt);
    int m = (l+r)/2;
    double res = 0;
    if(L <= m)
        res += query(ls,l,m,L,R);
    if(m < R)
        res += query(rs,m+1,r,L,R);
    return res;
}

int n,m;
int main ()
{
    //freopen("in.txt","r",stdin);
    while (scanf("%d",&n)!=EOF) {
        memset(lz,0,sizeof(lz));
        for(int i=1;i<=n;i++) {
            scanf("%lld", &val[i]);
        }
        build(1,1,n);
        scanf("%d", &m);
        while (m--){
            int op,l,r;
            scanf("%d %d %d",&op,&l,&r);
            if(op==1) {
                ll v; scanf("%lld",&v);
                update(1,1,n,l,r,v);
            }else {
                printf("%.1f
",query(1,1,n,l,r));
            }
        }
    }
    return 0;
}

 

以上是关于Wannafly 挑战赛22 D 整数序列 线段树 区间更新,区间查询的主要内容,如果未能解决你的问题,请参考以下文章

Wannafly挑战赛4

NowCoder Wannafly挑战赛22 A~D 一句话题解

Wannafly挑战赛22 A-计数器(gcd,裴蜀定理)

Wannafly挑战赛22游记

Wannafly挑战赛2 Cut

Wannafly挑战赛16 A 取石子