#10128. 「一本通 4.3 练习 2」花神游历各国(线段树)

题目描述

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

每一次旅行中,花神会选择一条旅游路线,它在那一串国家中是连续的一段,这次旅行带来的开心值是这些国家的喜欢度的总和,当然花神对这些国家的喜欢程序并不是恒定的,有时会突然对某些国家产生反感,使他对这些国家的喜欢度 δ 变为 sqrt(δ)(可能是花神虐爆了那些国家的 OI,从而感到乏味)。

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

输入格式

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

第二行有 N 个空格隔开的整数,表示每个国家的初始喜欢度 δ ;
第三行是一个整数 M,表示有 M 条信息要处理;

第四行到最后,每行三个整数 x,l,r, 当 x=1时询问游历国家 l到 r 的开心值总和;当 x=2 时,国家 l到 r 中每个国家的喜欢度 δ 变为sqrt(δ )。

输出格式

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

样例

Input

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

Output

101
11
11

代码

#include "bits/stdc++.h"
using namespace std;
#define ll long long
ll b[10000009],sum[10000009],book[10000009];
void built(ll k,ll l,ll r)//建立线段树 
{
	if(r==l)
	{
		sum[k]=b[l];
		if(sum[k]<=1)
			book[k]=1;//标记,sum[k]=1时,sqrt(1)=1,(0也一样)节省时间,不用再开根号的 
		return ;
	}
	ll mid=(l+r)/2;
	built(2*k,l,mid);
	built(2*k+1,mid+1,r);
	sum[k]=sum[2*k]+sum[2*k+1];
	if(book[2*k]&&book[2*k+1])//节点k下面的所有子节点都为1或0,则对k进行标记,不用再开根号了 
		book[k]=1;
	return ; 
}
void update(ll k,ll l,ll r,ll x,ll y)//更新数值 
{
	if(book[k]) return ;//节点k下面的所有子节点都为1或0,则对k进行标记,不用再开根号了 ,sum[k]的值不变 
	if(l==r)
	{
		sum[k]=sqrt(sum[k]);
		if(sum[k]<=1)
			book[k]=1;//标记,sum[k]=1时,sqrt(1)=1,(0也一样)节省时间,不用再开根号的 
		return ;
	}
	ll mid=(l+r)/2;
	if(x<=mid)
		update(2*k,l,mid,x,y);
	if(y>=mid+1)
		update(2*k+1,mid+1,r,x,y);
	sum[k]=sum[2*k]+sum[2*k+1];
	if(book[2*k]&&book[2*k+1])//节点k下面的所有子节点都为1或0,则对k进行标记,不用再开根号了 
		book[k]=1;
	return ;
		
}
ll add(ll k,ll l,ll r,ll x,ll y)//求[x,y]的开心度 
{
	if(x<=l&&r<=y)
		return sum[k];
	ll mid=(l+r)/2;
	ll s=0;
	if(x<=mid)
		s=add(2*k,l,mid,x,y);
	if(y>=mid+1)
		s+=add(2*k+1,mid+1,r,x,y);
	return s;
}
int main()
{
	ll n,q;
	cin>>n;
	for(ll i=1;i<=n;i++)
		cin>>b[i];
	built(1,1,n);//结点,[1,n]的区间 
	cin>>q;
	while(q--)
	{
		ll w,x,y;
		cin>>w>>x>>y;
		if(w==1)
			cout<<add(1,1,n,x,y)<<endl;
		else
			update(1,1,n,x,y);
	}
	
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值