2022牛客寒假算法基础集训营5 K造梦小孩

本文介绍了一位玩家在玩造梦西游时对角色唐僧的技能进行研究的过程,主要探讨了唐僧的水魔爆和玄冰阵技能的伤害计算,并针对不同技能给出了不同的数据结构和算法来高效处理地图上小怪的伤害统计。通过实例展示了如何计算特定范围内造成的总伤害,涉及到了树状数组和暴力查询等技术。

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

题目:造梦小孩

众所周知,九峰喜欢玩造梦西游。
孙悟空是造梦西游工作室的宠儿,从七魔王到上古天帝篇最强的角色都是孙悟空,九峰在用悟空通关了造梦西游1-5后决定重新玩一遍唐僧,希望能磨练自己的技术,而不是啥boss都无脑火魔斩就行了。于是他对唐僧的技能做了一些研究:
唐僧的攻击技能只有三种:
1.冰龙波,这是个废物技能,我们不会去用它
2.水魔爆,进行对点打击,破坏力巨大
3.玄冰阵,以人物为中心进行范围伤害,在左右一定距离处从地面向上穿出两颗冰刺,然后能量传递到两倍距离远处穿出同样的冰刺,三倍,四倍,以此类推无限扩张
九峰决定试一试除了冰龙波之外的技能,于是进入了VIP练习关卡,该关每个单位长度上都有一个无限血量的小怪,九峰会在图上乱放技能,但他有时候又想统计某个范围内造成的伤害总量,你能帮他算一算吗?
输入描述:
第一行输入两个正整数,表示地图长度和询问次数
接下来m行每行3或4个整数,格式如下:
1 x y: 表示九峰对x位置使用水魔爆并造成了y点伤害
2 x y len: 表示九峰在x位置使用了玄冰阵,对每个冰刺穿出的位置造成y点伤害,冰刺传递的距离为len
3 l r: 表示查询九峰对[l,r]区间的小怪一共造成了多少伤害
输出描述:
对于每个操作3,输出造成的伤害量
示例1
输入
复制
10 5
1 5 29
2 7 32 4
3 2 6
2 8 13 3
3 2 7
输出
复制
61
87
说明
三次技能对全图的伤害依次为:
[0,0,0,0,29,0,0,0,0,0]
[0,0,32,0,0,0,0,0,0,0]
[0,13,0,0,13,0,0,0,0,0]

分块题,操作1用树状数组维护,操作2当len< n \sqrt{n} n 时暴力做单点修改。
当len>= n \sqrt{n} n 时,用一个b[x][len]数组记录每次x开头长度为len的伤害,处理成前缀和,在查询时枚举len求和。

#include<bits/stdc++.h>
using namespace std;

namespace BIT{
	typedef long long ll;
	const int N=1e5;
	const ll inf=0x3f3f3f3f3f3f3f3f;
	
	int n;
	ll c[N+5];
	
	void init(int _n) {
		n=_n;
		for(int i=1;i<=n;i++) c[i]=0;
	}
	
	int lowbit(int x) {
		return x&-x;
	}
	
	void modify(int x,int d) {	//单点修改 
		for(int i=x;i<=n;i+=lowbit(i)) {
			c[i]+=d;
		}
	}
	
	ll query(int x) {	//单点询问 
		ll s=0;
		for(int i=x;i>0;i-=lowbit(i)) {
			s=s+c[i];
		}
		return s;
	}
}
using namespace BIT;

const int NN=4e2;
int nn;
ll b[NN+5][NN+5];	//b[x][len]
ll sum[NN+5][NN+5];

ll get(int x) {
	ll s=0; 
	for(int i=1;i<=nn;i++) {
		s+=(x/i)*sum[i][i]+sum[x%i][i];
	}
	return s;
}

int main() {
	std::ios::sync_with_stdio(false);
	
	int n,m;
	cin>>n>>m;
	init(n);
	nn=sqrt(n);
	
	while(m--) {
		int opr;
		cin>>opr;
		if(opr==1) {
			int x,y;
			cin>>x>>y;
			modify(x,y);
		} else if(opr==2) {
			int x,y,len;
			cin>>x>>y>>len;
			
			int st=x%len==0?len:x%len;
			
			if(len>nn) {
				for(int i=st;i<=n;i+=len) modify(i,y);
				modify(x,-y);
			} else {
				b[st][len]+=y;
				for(int i=1;i<=nn;i++) {
					sum[i][len]=b[i][len]+sum[i-1][len];
				}
				modify(x,-y);
			}
		} else {
			int l,r;
			cin>>l>>r;
			ll s=query(r)-query(l-1);
			s+=get(r)-get(l-1);
			cout<<s<<'\n';
		}
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值