博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

CF 914D 线段树维护区间gcd == x

题目大意

给定一个序列,支持两种操作:

  • 单点修改
  • 区间查询:是否存在一种方案,使得修改区间种0/1个元素后使得区间\(gcd = x\)

\(n \leq 5 \times 10^5\)

思路

查询时,记query函数返回值为当前区间至少修改多少个元素使得区间gcd是x的倍数。

查询时,对于每个区间只需要找到一个不是x的倍数的数字即可。

复杂度\(O(nlogn)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 5e5 + 10;

int n;
int a[N];
struct node {
	int l,r;
	int gcd;
}t[N << 2];

int gcd(int a,int b) {
	return b == 0 ? a : gcd(b,a % b);
}

void update(int rt) {
	int ch = rt << 1;
	t[rt].gcd = gcd(t[ch].gcd,t[ch + 1].gcd);
}

void build(int l,int r,int rt) {
	t[rt].l = l;
	t[rt].r = r;
	if(l == r) {
		t[rt].gcd = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	int ch = rt << 1;
	build(l,mid,ch);
	build(mid + 1,r,ch + 1);
	update(rt);
}

void modify(int x,int rt,int v) {
	if(t[rt].l == t[rt].r) {
		t[rt].gcd = v;
		return;
	}
	int mid = (t[rt].l + t[rt].r) >> 1;
	int ch = rt << 1;
	if(x <= mid) modify(x,ch,v);
	else modify(x,ch + 1,v);
	update(rt);
}

int query(int l,int r,int rt,int x) {
	if(t[rt].gcd % x == 0) return 0;
	if(l == t[rt].l and r == t[rt].r) {
		if(l == r) return 1;
		int ch = rt << 1;
		if(t[ch].gcd % x == 0) {
			return query(t[ch + 1].l,t[ch + 1].r,ch + 1,x);
		}
		if(t[ch + 1].gcd % x == 0) {
			return query(t[ch].l,t[ch].r,ch,x);
		}
		return 2;
	}
	int ch = rt << 1;
	int mid = (t[rt].l + t[rt].r) >> 1;
	if(r <= mid) {
		return query(l,r,ch,x);
	}else if(l > mid) {
		return query(l,r,ch + 1,x);
	}else {
		return query(l,mid,ch,x) + query(mid + 1,r,ch + 1,x);
	}
}

int main () {
	scanf("%d",&n);
	for (int i = 1;i <= n; i ++) {
		scanf("%d",&a[i]);
	}
	build(1,n,1);
	int q;
	cin >> q;
	while(q --) {
		int op;
		scanf("%d",&op);
		if(op == 1) {
			int l,r,x;
			scanf("%d %d %d",&l,&r,&x);
			int ans = query(l,r,1,x);
			if(ans <= 1) {
				puts("YES");
			}else puts("NO");
		}
		else {
			int x,y;
			scanf("%d %d",&x,&y);
			modify(x,1,y);
		}
	}
	return 0;
}
posted @ 2022-02-13 19:38  Allorkiya  阅读(14)  评论(0编辑  收藏  举报