CF914D Bash and a Tough Math Puzzle (线段树二分)

Description

给定一个序列 a a a,有 q q q 个询问,两个操作。

  • 1 l r x 猜测区间 [ l ,   r ] [l, r] [l,r] 中的 g c d gcd gcd x x x。你需要判断他的这个猜测是否是几乎正确的,几乎正确为:暂时修改任意一个数或不修改的情况下是正确的。
  • 2 i y a i a_i ai 改成 y y y

1 ≤ n ≤ 5 × 1 0 5 , 1 ≤ q ≤ 4 × 1 0 5 , 1 ≤ a i ≤ 1 0 9 1 \leq n \leq 5 \times 10^5, 1 \leq q \leq 4 \times 10^5, 1 \leq a_i \leq 10^9 1n5×105,1q4×105,1ai109

Solution

因为只能修改一个数,所以在线段树上二分找不是 x x x 倍数的数为 c n t cnt cnt。如 c n t > 1 cnt > 1 cnt>1NO,否则为 YES。方案为: c n t = 1 cnt=1 cnt=1 时将那个数变成 x x x c n t = 0 cnt = 0 cnt=0 随便选一个数变成 x x x

Code

#include <bits/stdc++.h>
const int N = 2e6 + 5;
#define lson p << 1
#define rson (p << 1) | 1
int a[N], cnt;
struct node{
	int l, r, val;
}tree[N];
int gcd(int a, int b){
	return b == 0 ? a : gcd(b, a % b);
}
void build(int p, int l, int r) {
	tree[p].l = l, tree[p].r = r;
	if (l == r){
		tree[p].val = a[l];
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid); build(rson, mid + 1, r);
	tree[p].val = gcd(tree[lson].val, tree[rson].val);
}
void update(int p, int x, int k) {
	if (tree[p].l == tree[p].r) {
		tree[p].val = k;
		return ;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (x <= mid) update(lson, x, k);
	else update(rson, x, k);
	tree[p].val = gcd(tree[lson].val, tree[rson].val);
}
void query(int p, int l, int r, int k) {
	if (cnt > 1) return ;
	if (tree[p].l == tree[p].r) {
		if (tree[p].val % k) cnt++;
		return ;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (l <= mid && tree[lson].val % k) query(lson, l, r, k);
	if (r > mid && tree[rson].val % k) query(rson, l, r, k);
}
int main(){
	int n, m; scanf("%d", &n);
	for (int i = 1; i <= n ;i++) scanf("%d", &a[i]);
	build(1, 1, n); 
	scanf("%d", &m); 
	while(m--) {
		int opt, l, r, k;
		scanf("%d%d%d", &opt, &l, &r);
		cnt = 0;
		if (opt == 1) {
			scanf("%d", &k), 
			query(1, l, r, k); 
			if (cnt <= 1) puts("YES"); 
			else puts("NO");
		}
		else update(1, l, r);
	}
	return 0;
}
posted @ 2020-02-20 11:03  ylxmf2005  阅读(30)  评论(0)    收藏  举报