GCD Problem (线段树区间GCD+区间开方)

题目描述输入描述:

输出描述:

输入

4
5 45 20 65
7
1 1 4
0 1 4
1 1 4
1 3 4
0 3 4
1 3 4
1 2 2

输出

5
2
4
2
6

            两个操作,一个是区间开方,一个是输出区间GCD;gcd很好处理。主要是开放这个操作,假设区间sum==l-r+1就return,不是的话就取找辣个还不是1的点去单点更新,这样最多更新nlogn*8次左右(可能没算错~)~~就行了

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const int maxn = 2e5 + 10;
ll gcd[maxn << 2], sum[maxn << 2];
long long GCD(long long a, long long b) {
	return b ? GCD(b, a%b) : a;
}
void pushup(int rt) {
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
	gcd[rt] = GCD(gcd[rt << 1], gcd[rt << 1 | 1]);
}
void build(int l, int r, int rt) {
	if (l == r) {
		scanf("%lld", &sum[rt]);
		gcd[rt] = sum[rt];
		return;
	}
	int m = (l + r) >> 1;
	build(lson); build(rson);
	pushup(rt);
}
void updates(int L, int R, int l, int r, int rt) {
	if (sum[rt] == r - l + 1)return;
	if (l == r) {
		sum[rt] = sqrt(sum[rt]);
		gcd[rt] = sum[rt];
		return;
	}
	int m = (l + r) >> 1;
	if (L <= m)updates(L, R, lson);
	if (m < R)updates(L, R, rson);
	pushup(rt);
}
ll query(int L, int R, int l, int r, int rt) {
	if (L <= l&&r <= R) {
		return gcd[rt];
	}
	int m = (l + r) >> 1;
	ll ans;
	if (L <= m) {
		ans = query(L, R, lson);
		if (m < R) 
			ans = GCD(ans, query(L, R, rson));
	}
	else ans = query(L, R, rson);
	return ans;
}
int main() {
	int n;
	scanf("%d", &n);
	build(1, n, 1);
	int q; scanf("%d", &q);
	while (q--) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		if (a == 1) {
			printf("%lld\n", query(b, c, 1, n, 1));
		}
		else {
			updates(b, c, 1, n, 1);
		}
	}
	return 0;
}

 

全部评论

相关推荐

一个菜鸡罢了:哥们,感觉你的简历还是有点问题的,我提几点建议,看看能不能提供一点帮助 1. ”新余学院“别加粗,课程不清楚是否有必要写,感觉版面不如拿来写一下做过的事情,教育经历是你的弱势就尽量少写 2. “干部及社团经历”和“自我评价”删掉 3. 论文后面的“录用”和“小修”啥的都删掉,默认全录用,问了再说,反正小修毕业前肯定能发出来 4. 工作经验和研究成果没有体现你的个人贡献,着重包装一下个人贡献
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务