线段树进阶总结二 (区间取模开根)

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

洛谷 区间开根

最多开几次根就变成1了 这里我们选择 维护区间 和 如果区间和等于区间长度 不更新
不等于 更新到底 反正最多跟新不了几次
正好问的也是区间和。。

#include 
#include 
using namespace std;
typedef long long ll;

const int maxn = 100050;
ll n, k;

ll tree[maxn << 2];

void pushup(int rt) {
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}

void build(int l, int r, int rt) {
	if(l == r) {
		scanf("%lld", &tree[rt]);
		return ;
	}
	int m = (l + r) >> 1;
	build(l, m, rt << 1);
	build(m + 1, r, rt << 1 | 1);
	pushup(rt);
}

void update(int L, int R, int l, int r, int rt) {
	if(L <= l && r <= R && tree[rt] == (ll)(r - l + 1)) return;
	if(l == r) {
		tree[rt] = sqrt(1.0 * tree[rt]);
		return;
	}
	int m = (l + r) >> 1;
	if(L <= m)
		update(L, R, l, m, rt << 1);
	if(R > m)
		update(L, R, m + 1, r, rt << 1 | 1);
	pushup(rt);
}

ll query(int L, int R, int l, int r, int rt) {
	if(L <= l && r <= R) return tree[rt];
	int m = (l + r) >> 1;
	ll res = 0;
	if(L <= m)
		res += query(L, R, l, m, rt << 1);
	if(R > m)
		res += query(L, R, m + 1, r, rt << 1 | 1);
	return res;
}

int main() {
	cin >> n;
	build(1, n, 1);
	cin >> k;
	for(int i = 0; i < k; i++) {
		int cmd, l, r;
		cin >> cmd >> l >> r;
		if(r < l) swap(r, l);
		if(cmd == 0) update(l, r, 1, n, 1);
		if(cmd == 1) printf("%lld\n", query(l, r, 1, n, 1));
	}
	return 0;
}

区间取模

CF - 438D
https://codeforces.com/problemset/problem/438/D
和上面一样 其实也就是看最大值 取模 只要能取 就一定让 当前数据 减低一半
所以接着暴力更

#include 
#include 
using namespace std;
typedef long long ll;

const int maxn = 100050;
ll n, k;

ll tree[maxn << 2], mas[maxn << 2];

void pushup(int rt) {
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
	mas[rt] = max(mas[rt << 1], mas[rt << 1 | 1]);
}

void build(int l, int r, int rt) {
	if(l == r) {
		scanf("%lld", &tree[rt]);
		mas[rt] = tree[rt];
		return ;
	}
	int m = (l + r) >> 1;
	build(l, m, rt << 1);
	build(m + 1, r, rt << 1 | 1);
	pushup(rt);
}

void update(int L, int R, int l, int r, int rt, int p) {
	if(L <= l && r <= R && mas[rt] < p) return;
	if(l == r) {
		tree[rt] = tree[rt] % p;
		mas[rt] = tree[rt];
		return;
	}
	int m = (l + r) >> 1;
	if(L <= m) update(L, R, l, m, rt << 1, p);
	if(R > m) update(L, R, m + 1, r, rt << 1 | 1, p);
	pushup(rt);
}

void upd(int L, int l, int r, int rt, int val) {
	if(l == r) {
		tree[rt] = val;
		mas[rt] = val;
		return;
	}
	int m = (l + r) >> 1;
	if(L <= m) upd(L, l, m, rt << 1, val);
	else upd(L, m + 1, r, rt << 1 | 1, val);
	pushup(rt);
}

ll query(int L, int R, int l, int r, int rt) {
	if(L <= l && r <= R) return tree[rt];
	int m = (l + r) >> 1;
	ll res = 0;
	if(L <= m) res += query(L, R, l, m, rt << 1);
	if(R > m) res += query(L, R, m + 1, r, rt << 1 | 1);
	return res;
}

int main() {
	cin >> n >> k;
	build(1, n, 1);
	for(int i = 0; i < k; i++) {
		int cmd, l, r, p;
		cin >> cmd >> l >> r;
		if(cmd == 3) upd(l, 1, n, 1, r);
		if(cmd == 2) cin >> p, update(l, r, 1, n, 1, p);
		if(cmd == 1) printf("%lld\n", query(l, r, 1, n, 1));
	}
	return 0;
}

你可能感兴趣的:(线段树)