[洛谷 P4145] 上帝造题的七分钟2 / 花神游历各国(暴力线段树) | 错题本

文章目录

题目

[洛谷 P4145] 上帝造题的七分钟2 / 花神游历各国

分析

每个数不断开根下取整,最终会变成 1 1 1,显而易见的是只需要开极少的次数一个数就能变成一,这个次数是 log ⁡ 2 log ⁡ 2 n + 1 \log_2\log_2 n + 1 log2log2n+1。因此线段树区间修改时如果该区间没有全部变成 1 1 1,就暴力一个一个改即可。

代码

#include <bits/stdc++.h>

typedef long long LL;

LL Read() {
	LL x = 0; bool f = false; char c = getchar();
	while (c < '0' || c > '9')
		f |= c == '-', c = getchar();
	while (c >= '0' && c <= '9')
		x = x * 10 + (c ^ 48), c = getchar();
	return f ? -x : x;
}

const int MAXN = 100000;

int N, Q;

#define lch (u << 1)
#define rch (u << 1 | 1)

struct Node {
	LL tot;
	bool flg;

	Node operator + (const Node &other) const {
		return { tot + other.tot, flg && other.flg };
	}
} T[MAXN * 4 + 5];

void Build(const int &u, const int &l, const int &r) {
	if (l == r) {
		T[u].flg = false;
		T[u].tot = Read();
		return;
	}
	int mid = (l + r) >> 1;
	Build(lch, l, mid);
	Build(rch, mid + 1, r);
	T[u] = T[lch] + T[rch];
}

void Sqrt(const int &u, const int &l, const int &r, const int &lft, const int &rgt) {
	if (T[u].flg) return;
	if (l == r) {
		T[u].tot = (LL)sqrt(T[u].tot + 0.1);
		if (T[u].tot == 1) T[u].flg = true;
		return;
	}
	int mid = (l + r) >> 1;
	if (lft <= mid) Sqrt(lch, l, mid, lft, rgt);
	if (mid + 1 <= rgt) Sqrt(rch, mid + 1, r, lft, rgt);
	T[u] = T[lch] + T[rch];
}

LL Query(const int &u, const int &l, const int &r, const int &lft, const int &rgt) {
	if (lft <= l && r <= rgt) return T[u].tot;
	int mid = (l + r) >> 1; LL ret = 0;
	if (lft <= mid) ret = Query(lch, l, mid, lft, rgt);
	if (mid + 1 <= rgt) ret += Query(rch, mid + 1, r, lft, rgt);
	return ret;
}

int main() {
//	int Case = 0;
	while (~scanf("%d", &N)) {
		Build(1, 1, N);
		Q = Read();
//		printf("Case #%d:\n", ++Case);
		while (Q--) {
			int opt = Read(), l = Read(), r = Read();
			if (l > r) std::swap(l, r);
			if (opt) printf("%lld\n", Query(1, 1, N, l, r));
			else Sqrt(1, 1, N, l, r);
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值