花神游历各国(线段树 单修区查和)

这篇博客介绍了一个线段树的应用实例,用于解决旅行开心值计算的问题。花神在各国旅行,每次选择一段连续的国家,其开心值由这些国家的喜欢程度总和决定。题目中给出了初始的喜欢程度,以及后续的区间修改和查询操作。线段树在这里被用来高效地处理区间修改和区间查询,确保在大数据范围内的性能。博主提供了AC代码,并特别指出在更新区间最大值时的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

花神游历各国(线段树 单修区查和)

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

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

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

输入格式
第一行是一个整数 N,表示有 N 个国家;

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

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

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

输出格式
每次 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

数据范围与提示
对于全部数据,1≤n≤10 5 ,1≤m≤2×10 5,1≤l≤r≤n, 0≤δ i≤10 9

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

思路: 算是一个线段树单修求区间和的一个板,用en-st+1=t[rt] 会超时,所以要再开一个maxx[]记录区间最大值

AC代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#define ll long long
#define lef st,mid,rt<<1
#define rig mid+1,en,rt<<1|1
#include<algorithm>
using namespace std;
const int N=1e6+10;
ll t[N],a[N],maxx[N];
ll n,m,l,r,ans;
void ud(ll rt)
{
	t[rt]=t[rt<<1]+t[rt<<1|1];
	maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(ll st,ll en,ll rt)
{
	if(st==en)
		maxx[rt]=t[rt]=a[en];
	else
	{
		ll mid=(st+en)>>1;
		build(lef);
		build(rig);
		ud(rt);
	}
}
void update(ll st,ll en,ll rt)
{
	//if(en-st+1==t[rt]) return ;
	if(maxx[rt]<=1) return;
	if(st==en) t[rt]=sqrt(t[rt]),maxx[rt]=t[rt];//
	else
	{
		ll mid=(st+en)>>1;
		if(l<=mid)
			update(lef);
		if(r>mid)
			update(rig);
		ud(rt);
	}
}
ll query(ll st,ll en,ll rt)
{
	if(st>r||en<l) return 0;
	/*if(en-st+1==t[rt])
	return ans+=(min(en,r)-max(st,l)+1);//
	//if(st==en) return t[rt];
	*/
	if(l<=st&&en<=r) return t[rt];//
	//ans=0;
	ll mid=(st+en)>>1;
	if(r<=mid) return query(lef);//全在左区间,返左边
	else if(l>mid) return query(rig);//全在右区间,返右边
	else//两边都有
	{
		ll le=query(lef);//
		ll ri=query(rig);//
		return le+ri;
	}
}
int main()
{
	ll i,j,k;
	scanf("%lld",&n);
	for(i=1; i<=n; i++)
		scanf("%lld",&a[i]);
	build(1,n,1);
	scanf("%lld",&m);
	while(m--)
	{
		ll x;
		//ans=0;
		scanf("%lld%lld%lld",&x,&l,&r);
		if(x==1)
			printf("%lld\n",query(1,n,1));
		else
			update(1,n,1);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值