#线段树,树状数组#CH 4302 Interval GCD

本文介绍了一种解决区间修改和区间查询最大公因数(GCD)问题的有效算法。通过使用差分数组将区间修改转化为单点修改,并利用线段树支持快速查询GCD,实现了高效的数据结构操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

满足区间修改和区间求最大公因数


分析

根据更相减损法,gcd(x,y)=gcd(x,y−x)gcd(x,y)=gcd(x,y-x)gcd(x,y)=gcd(x,yx),所以可以用一个差分序列b[i]=a[i]−a[i−1]b[i]=a[i]-a[i-1]b[i]=a[i]a[i1],区间修改变成单点修改,对于每个求最大公因数的操作,可以等价转化为gcd(a[l]+answer(l),ask(1,1,n,l+1,r))gcd(a[l]+answer(l),ask(1,1,n,l+1,r))gcd(a[l]+answer(l),ask(1,1,n,l+1,r))


代码

#include <cstdio>
#define N 500001
typedef long long ll;
ll w[N<<2],c[N],n,m,a[N];
ll in(){
	ll ans=0; char c=getchar(); int f=1;
	while ((c<48||c>57)&&c!='-') c=getchar();
	if (c=='-') c=getchar(),f=-f;
	while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
	return ans*f;
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void build(int k,int l,int r){
	if (l==r) {w[k]=a[l]-a[l-1]; return;}//差分
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	w[k]=gcd(w[k<<1],w[k<<1|1]);//求最大公因数
}
ll abs(ll x){return (x>0)?x:-x;}
void print(ll ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
ll answer(int x){ll ans=0ll;while (x) ans+=c[x],x-=-x&x; return ans;}//求增减的答案
void add(int x,ll y){while (x<=n) c[x]+=y,x+=-x&x;}
ll ask(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return abs(w[k]);
	int mid=(l+r)>>1;
	if (y<=mid) return ask(k<<1,l,mid,x,y);
	else if (x>mid) return ask(k<<1|1,mid+1,r,x,y);
	else return abs(gcd(ask(k<<1,l,mid,x,mid),ask(k<<1|1,mid+1,r,mid+1,y)));//中间的最大公因数
}
void update(int k,int l,int r,int x,ll y){
	if (l==r) {w[k]+=y; return;}
	int mid=(l+r)>>1;
	if (x<=mid) update(k<<1,l,mid,x,y); else update(k<<1|1,mid+1,r,x,y);
	w[k]=gcd(w[k<<1],w[k<<1|1]);
}
int main(){
	n=in(); m=in();
	for (register int i=1;i<=n;i++) a[i]=in();
	build(1,1,n); 
	while (m--){
		char c=getchar(); int l,r;
		while (c<65||c>90) c=getchar();
		if (c=='Q'){
			l=in(); r=in();
			ll ans=gcd(a[l]+answer(l),ask(1,1,n,l+1,r));//求答案
			if (ans) print(ans); else putchar('0'); putchar('\n');
		}
		else {
			l=in(); r=in(); ll t=in();
			add(l,t),update(1,1,n,l,t); //单点修改
			add(r+1,-t); if (r<n) update(1,1,n,r+1,-t);//单点修改
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值