花神游历各国 - 线段树开方

1550:花神游历各国


时间限制: 1000 ms         内存限制: 524288 KB
提交数: 127     通过数: 47

【题目描述】

原题来自:BZOJ 3211

花神喜欢步行游历各国,顺便虐爆各地竞赛。花神有一条游览路线,它是线型的,也就是说,所有游历国家呈一条线的形状排列,花神对每个国家都有一个喜欢程度(当然花神并不一定喜欢所有国家)。

每一次旅行中,花神会选择一条旅游路线,它在那一串国家中是连续的一段,这次旅行带来的开心值是这些国家的喜欢度的总和,当然花神对这些国家的喜欢程序并不是恒定的,有时会突然对某些国家产生反感,使他对这些国家的喜欢度 δ

变为 δ

(可能是花神虐爆了那些国家的 OI,从而感到乏味)。

现在给出花神每次的旅行路线,以及开心度的变化,请求出花神每次旅行的开心值。

【输入】

第一行是一个整数 N,表示有 N个国家;

第二行有 N个空格隔开的整数,表示每个国家的初始喜欢度 δi

第三行是一个整数 M,表示有 M条信息要处理;

第四行到最后,每行三个整数 x,l,r,当 x=1 时询问游历国家 lr 的开心值总和,就是 ∑ri=lδi ,当 x=2 时国家 lr 中每个国家的喜欢度 δi变为 δi−−√。

【输出】

每次 x=1

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

【输入样例】

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

【输出样例】

101
11
11

【提示】

数据范围与提示:

对于全部数据,1≤n≤105,1≤m≤2×105,1≤lrn,0≤δi≤109。

注:建议使用 sqrt

函数,且向下取整。

思路:

这个题是要求开方的,我们可以知道,一个数多开几次都会变成1,所以用flag标记,flag=1时表示不用开方了。

代码如下:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=4e8;
const int N=100015,mod=32767;

ll sum[N<<2];
int flag[N<<2];

void push_up(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    flag[rt]=flag[rt<<1]&&flag[rt<<1|1];
}

void build(int l,int r,int rt){
    if(l==r){
        scanf("%lld",&sum[rt]);
        if(sum[rt]<=1)flag[rt]=1;
        return ;
    }
    int m=(r+l)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

void push_down(int l,int r,int rt){
    if(!flag[rt]){
        if(l==r){
            sum[rt]=floor(sqrt(sum[rt]));
            if(sum[rt]<=1)flag[rt]=1;
            return ;
        }
        int m=(l+r)>>1;
        push_down(lson);
        push_down(rson);
        push_up(rt);
    }
}

ll query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r){
        return sum[rt];
    }
    int m=(l+r)>>1;
    ll ans=0;
    if(L<=m)ans+=query(L,R,lson);
    if(R>m)ans+=query(L,R,rson);
    return ans;
}

void update(int L,int R,int l,int r,int rt){
    if(flag[rt])return ;
    if(L<=l&&r<=R){
        push_down(l,r,rt);
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m)update(L,R,lson);
    if(R>m)update(L,R,rson);
    push_up(rt);
}

int main(){
    int n,m,k,a,b;
    scanf("%d",&n);
    build(1,n,1);
    scanf("%d",&m);
    while(m--){
        scanf("%d%d%d",&k,&a,&b);
        if(k==1){
            printf("%lld\n",query(a,b,1,n,1));
        }
        else{
            update(a,b,1,n,1);
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值