cf914D. Bash and a Tough Math Puzzle(线段树)

题意

题目链接

Sol

直接在线段树上二分

当左右儿子中的一个不是(x)的倍数就继续递归

由于最多递归到一个叶子节点,所以复杂度是对的

开始时在纠结如果一段区间全是(x)的两倍是不是需要特判,实际上是不需要的。

可以这么想,如果能成功的话,我们可以把那个数改成(1),这样比(x)大的数就不会对答案产生影响了。

不过我的线段树为啥要开6倍空间才能过。。真是狗血、、

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e6 + 10, INF = 1e9 + 10;
inline int read() {
	char c = getchar(); int x = 0, f = 1;
	while(c < '0' || c > '9') {if(c == '-')f =- 1; c = getchar();}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}
int N, M, a[MAXN];
#define ls k << 1
#define rs k << 1 | 1 
struct Node {
	int l, r, g;
}T[MAXN];
int gcd(int a, int b) {
	return (b == 0 ? a : gcd(b, a % b));
}
void update(int k) {
	T[k].g = gcd(T[ls].g, T[rs].g);
}
void Build(int k, int ll, int rr) {
	T[k] = (Node) {ll, rr};
	if(ll == rr) {T[k].g = a[ll]; return ;}
	int mid = T[k].l + T[k].r >> 1;
	Build(ls, ll, mid); Build(rs, mid + 1, rr);
	update(k);
}
void PointChange(int k, int pos, int val) {
	if(T[k].l == T[k].r) {T[k].g = val; return ;}
	int mid = T[k].l + T[k].r >> 1;
	if(pos <= mid) PointChange(ls, pos, val); 
	else PointChange(rs, pos, val);
	update(k);
}
int sum = 0;
void IntervalTims(int k, int ll, int rr, int val) {
	if(sum > 1) return ;
	if(T[k].l == T[k].r) sum++;
	int mid = T[k].l + T[k].r >> 1;
	if(ll <= mid && (T[ls].g % val)) IntervalTims(ls, ll, rr, val);
	if(rr  > mid && (T[rs].g % val)) IntervalTims(rs, ll, rr, val);
}
main() {
	N = read();
	for(int i = 1; i <= N; i++) a[i] = read();
	Build(1, 1, N);
	M = read();
	while(M--) {
		int opt = read();
		if(opt == 1) {
			int l = read(), r = read(), x = read();
			sum = 0; IntervalTims(1, l, r, x);
			puts(sum > 1 ? "NO" : "YES");
		} else {
			int pos = read(), x = read();
			PointChange(1, pos, x);
		}
	}
}
/*
*/

原文地址:https://www.cnblogs.com/zwfymqz/p/9741528.html