花神游历各国-线段树(题解)

Description

花神喜欢步行游历各国,顺便虐爆各地竞赛。花神有一条游览路线,它是线型的,也就是说,所有游历国家呈一条线的形状排列,花神对每个国家都有一个喜欢程度(当然花神并不一定喜欢所有国家)。
每一次旅行中,花神会选择一条旅游路线,它在那一串国家中是连续的一段,这次旅行带来的开心值是这些国家的喜欢度的总和,当然花神对这些国家的喜欢程序并不是恒定的,有时会突然对某些国家产生反感,使他对这些国家的喜欢度由t 变为sqrt(t),
(可能是花神虐爆了那些国家的 OI,从而感到乏味)。现在给出花神每次的旅行路线,以及开心度的变化,请求出花神每次旅行的开心值。

Input

一行是一个整数 N,表示有 N 个国家;
第二行有 N 个空格隔开的整数,表示每个国家的初始喜欢度ti
第三行是一个整数 M,表示有 M 条信息要处理;
第四行到最后,每行三个整数 x,l,r,当 x=1 时询问游历国家 l 到 r 的开心值总和,当 x=2 时国家 l 到 r 中每个国家的喜欢度由ti变成sqrt(ti); 

Output

每次 x=1 时,每行一个整数。表示这次旅行的开心度。

Sample Input

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

Sample Output

101
11
11

思路:

一般对于区间加乘操作,可以用lazy标记,但像这样对每个数取根号,除去一个整数,并且不增加数的大小,由于对每个数操作次数不会太高,所以可以对每个数单独操作,再加上一个数组标记,当一个区间都不必再操作,就直接return即可。

代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
using namespace std;
const int N = 1e5 + 10;
#define ls (o<<1)
#define rs (o<<1|1)
long long  sum[N << 2];
long long  aa[N << 2];
bool bb[N << 2];//
int  k, a, b, m, c, n, x;
long long p;
void build(int o, int l, int r)
{
    if (l == r)
    {
        sum[o] = aa[l];
        if (sum[o] == 1 || sum[o] == 0)
            bb[o] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(ls, l, mid);
    build(rs, mid + 1, r);
    sum[o] = sum[ls] + sum[rs];
}
void change(int o, int l, int r, int ql, int qr)
{
    if (l == r)
    {
        sum[o] = (long long)sqrt(sum[o]);
        if (sum[o] == 1 || sum[o] == 0)
            bb[o] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    if (ql <= mid && bb[ls] == 0)
        change(ls, l, mid, ql, qr);
    if (mid + 1 <= qr && bb[rs] == 0)
        change(rs, mid + 1, r, ql, qr);
    sum[o] = sum[ls] + sum[rs];
    if (bb[ls] && bb[rs])//当区间都不在用取根号时就标记
        bb[o] = 1;
}
long long  ask(int o, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
        return sum[o];
    int mid = (l + r) >> 1;
    long long ans = 0;
    if (ql <= mid)
        ans = ans + ask(ls, l, mid, ql, qr);
    if (mid + 1 <= qr)
        ans = ans + ask(rs, mid + 1, r, ql, qr);
    return ans;
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        scanf("%lld", &aa[i]);
    build(1, 1, n);
    cin >> m;
    for (int i = 1; i <= m; i++)
    {
        int y;
        scanf("%d", &y);
        if (y == 1)
        {
            scanf("%d%d", &a, &b);
            printf("%lld\n", ask(1, 1, n, a, b));
        }
        else
        {
            scanf("%d%d", &a, &b);
            change(1, 1, n, a, b);
        }
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值