花神游历各国(线段树)

题目描述:

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

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

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

输入格式:

第一行是一个整数N,表示有N个国家;
第二行有N个空格隔开的整数,表示每个国家的初始喜欢度;
第三行是一个整数M,表示有M条信息要处理;
第四行到最后,每行三个整数想x,l,r,当x=1时询问游历国家x到r的开心值总和,也就是Σδi(l~r),当x=2时国家l到r中每个国家的喜欢度δ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≤l≤r≤n,0≤δi≤109。

注:建议使用sqrt函数,且向下取整。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;//开四倍空间 
ll a[N],sum[N],ma[N];//ma[]记录最大开根值 
ll n,m;
void build(int k,int l,int r)
{
	if(l==r){
		sum[k]=ma[k]=a[l];
		return ;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	sum[k]=sum[k<<1]+sum[k<<1|1];
	ma[k]=max(ma[k<<1],ma[k<<1|1]);
}
void update(int k,int l,int r,int x,int y)
{
	if(ma[k]==1||ma[k]==0) return ;//开根遇到1和0直接跳出 
	if(l==r){
		ma[k]=sum[k]=sqrt(sum[k]);
		return ;
	}
	int mid=l+r>>1;
	if(x<=mid) update(k<<1,l,mid,x,y);
	if(mid<y) update(k<<1|1,mid+1,r,x,y);
	sum[k]=sum[k<<1]+sum[k<<1|1];
	ma[k]=max(ma[k<<1],ma[k<<1|1]);
}
ll query(int k,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return sum[k];
	int mid=l+r>>1;
	ll res=0;
	if(x<=mid) 
		res+=query(k<<1,l,mid,x,y);
	if(y>mid) 
		res+=query(k<<1|1,mid+1,r,x,y);
	return res;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	cin>>m;
	while(m--){
		int x,y,z;
		cin>>x>>y>>z;
		if(x==1)
			cout<<query(1,1,n,y,z)<<endl;
		else
			update(1,1,n,y,z);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值