1. 程式人生 > >Bash and a Tough Math Puzzle CodeForces - 914D (線段樹)

Bash and a Tough Math Puzzle CodeForces - 914D (線段樹)

序列 單點 () void mes 意思 span esp sin

大意:給定序列, 單點修改, 區間詢問$[l,r]$內修改至多一個數後$gcd$能否為$x$

這題比較有意思了, 要註意到詢問等價於$[l,r]$內最多有1個數不為$x$的倍數

可以用線段樹維護gcd, 詢問操作每次二分找第一個不為$x$的倍數的數, 若找到兩個直接返回, 是$O(logn)$的

單點更新要大量計算gcd, 是$O(log^2n)$的

#include <iostream>
#include <algorithm>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc (lc|1)
#define ls lc,l,mid
#define rs rc,mid+1,r
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}

const int N = 5e5+10, INF = 0x3f3f3f3f;
int n, m;
int g[N<<2];

void build(int o, int l, int r) {
	if (l==r) return scanf("%d", g+o), void();
	build(ls),build(rs);
	g[o]=gcd(g[lc],g[rc]);
}
void upd(int o, int l, int r, int x, int v) {
	if (l==r) return g[o]=v,void();
	if (mid>=x) upd(ls,x,v);
	else upd(rs,x,v);
	g[o]=gcd(g[lc],g[rc]);
}
int query(int o, int l, int r, int ql, int qr, int v) {
	if (!(g[o]%v)) return 0;
	if (l==r) return 1;
	int ans = 0;
	if (mid>=ql) {
		ans += query(ls,ql,qr,v);
		if (ans>1) return ans;
	}
	if (mid<qr) ans += query(rs,ql,qr,v);
	return ans;
}

int main() {
	scanf("%d", &n);
	build(1,1,n);
	scanf("%d", &m);
	REP(i,1,m) {
		int op, l, r, x, v;
		scanf("%d", &op);
		if (op==1) {
			scanf("%d%d%d", &l, &r, &v);
			puts(query(1,1,n,l,r,v)<=1?"YES":"NO");
		} else {
			scanf("%d%d", &x, &v);
			upd(1,1,n,x,v);
		}
	}
}

Bash and a Tough Math Puzzle CodeForces - 914D (線段樹)