洛谷 P10463 Interval GCD 做题记录

前置芝士:线段树,辗转相减

思路

首先我们有 \(\gcd(a,b)=\gcd(b,a-b)\)
题目要求区间 \([l,r]\)\(gcd\),等同于求 \(\gcd_{i=l}^{r} a_i\)
那么根据辗转相减法,上面这个式子等同于 \(\gcd(a_l,\gcd_{i=l+1}^{r} a_i-a_{i-1})\)
那么这下就简单了。
我们用线段树维护区间的 \(gcd\) 即可。对 \([l,r]\) 区间加,相当于在差分数组上对 \(l\) 单点加和 \(r+1\) 单点减。

时间复杂度:\(O(n\log n)\)
难点/坑点:因为会用到 \(r+1\) 可能会大于 \(n\) 所以要记得对 \(n\) 加一。

点击查看代码
#include<bits/stdc++.h>

#define int ll
#define pii pair<int,int> 
#define pll pair<long long,long long> 
#define ll long long
#define i128 __int128

#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define in4(a,b,c,d) a=read(), b=read(), c=read(), d=read()
#define fst first 
#define scd second 
#define dbg puts("IAKIOI")

using namespace std;

int read() {
	int x=0,f=1; char c=getchar();
	for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1); 
	for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	return x*f;
}
void write(int x) { if(x<0) return write(-x); if(x>=10) write(x/10); putchar('0'+x%10); }

const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }

#define maxn 500050

int n,m,a[maxn];

struct SegT {
	int tr[maxn<<2],sum[maxn<<2];
	
	void psu(int idx) {
		tr[idx]=__gcd(tr[lc(idx)],tr[rc(idx)]);
		sum[idx]=sum[lc(idx)]+sum[rc(idx)];
	}
	void build(int idx,int l,int r,int a[]) {
		if(l==r) {
			tr[idx]=a[l]-a[l-1];
			sum[idx]=a[l]-a[l-1];
			return ;
		}
		int mid=l+r>>1;
		build(lc(idx),l,mid,a);
		build(rc(idx),mid+1,r,a);
		psu(idx);
	}
	void upd(int idx,int l,int r,int k,int val) {
		if(l==r) return tr[idx]+=val,sum[idx]+=val,void();
		int mid=l+r>>1;
		if(k<=mid) upd(lc(idx),l,mid,k,val);
		else upd(rc(idx),mid+1,r,k,val);
		psu(idx);
	}
	int qgcd(int idx,int l,int r,int L,int R) {
		if(L<=l&&r<=R) return tr[idx];
		int res=0,mid=l+r>>1;
		if(L<=mid) res=qgcd(lc(idx),l,mid,L,R);
		if(R>mid) res=__gcd(res,qgcd(rc(idx),mid+1,r,L,R));
		return res;
	}
	int qsum(int idx,int l,int r,int L,int R) {
		if(L<=l&&r<=R) return sum[idx];
		int res=0,mid=l+r>>1;
		if(L<=mid) res=qsum(lc(idx),l,mid,L,R);
		if(R>mid) res+=qsum(rc(idx),mid+1,r,L,R);
		return res;
	}
}segtr;

void work() {
	in2(n,m);
	For(i,1,n) in1(a[i]);
	segtr.build(1,1,n+1,a);
	For(i,1,m) {
		char ch=getchar();
		while(ch!='C'&&ch!='Q') ch=getchar();
		int l,r; in2(l,r);
		if(ch=='C') {
			int d=read();
			segtr.upd(1,1,n+1,l,d);
			segtr.upd(1,1,n+1,r+1,-d);
		} else {
			cout<<abs(__gcd(segtr.qgcd(1,1,n+1,l+1,r),segtr.qsum(1,1,n+1,1,l)))<<'\n';
		}
	}
}

signed main() {
//	freopen("data.in","r",stdin);
//	freopen("myans.out","w",stdout);
//	ios::sync_with_stdio(false); 
//	cin.tie(0); cout.tie(0);
	double stt=clock();
	int _=1;
//	_=read();
//	cin>>_;
	For(i,1,_) {
		work();
	}
	cerr<<"\nTotal Time is:"<<(clock()-stt)*1.0/1000<<" second(s)."<<'\n';
	return 0;
}
posted @ 2025-03-28 15:44  coding_goat_qwq  阅读(38)  评论(0)    收藏  举报