【CH 4302】Interval GCD

【题目】

传送门

题目描述:

给定一个长度为 n n n 的数列 a a a,以及 m m m 条指令 ( n ≤ 5 × 1 0 5 , m ≤ 1 0 5 ) (n≤5\times10^5, m\le10^5) (n5×105,m105),每条指令可能是以下两种之一:

“ C    l    r    d ” “C\; l\; r\; d” Clrd,表示把 a l , a l + 1 , … , a r a_l,a_{l+1},…,a_r al,al+1,,ar 都加上 d d d
“ Q    l    r ” “Q\; l \;r” Qlr,表示询问 a l , a l + 1 , … , a r a_l,a_{l+1},…,a_r al,al+1,,ar 的最大公约数 ( g c d ) (gcd) (gcd)

输入格式:

第一行两个整数 n , m n,m n,m,第二行 n n n 个整数 a i a_i ai,接下来 m m m 行每条指令的格式如题目描述所示。

输出格式:

对于每个询问,输出一个整数表示答案。

样例数据:

输入
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4

输出
1
2
4

数据范围与约定:

n , m ≤ 2 × 1 0 5 n,m≤2\times10^5 n,m2×105 l ≤ r l\le r lr,数据保证任何时刻序列中的数都是不超过 2 62 − 1 2^{62}-1 2621的正整数。


【分析】

数据范围为什么都不统一啊。。。

做这道题之前,要先知道一个东西,叫做辗转相减法

有一个关于它的推论,即 g c d ( x , y , z ) = g c d ( x , y − x , z − y ) gcd(x,y,z)=gcd(x,y-x,z-y) gcd(x,y,z)=gcd(x,yx,zy),推广到 n n n 个数也成立

这里还是简单证一下(如果有错请提出来)
假设 g c d ( x , y , z ) = a gcd(x,y,z)=a gcd(x,y,z)=a,那么必有互质的三个数 m 1 , m 2 , m 3 m_1,m_2,m_3 m1,m2,m3 使 x = m 1 a , y = m 2 a , z = m 3 a x=m_1a,y=m_2a,z=m_3a x=m1a,y=m2a,z=m3a
那么 g c d ( x , y − x , z − y ) = g c d ( m 1 a , ( m 2 − m 1 ) a , ( m 3 − m 2 ) a ) gcd(x,y-x,z-y)=gcd(m_1a,(m_2-m_1)a,(m_3-m_2)a) gcd(x,yx,zy)=gcd(m1a,(m2m1)a,(m3m2)a)
由于 m 1 , m 2 , m 3 m_1,m_2,m_3 m1,m2,m3 互质,所以 m 1 , m 2 − m 1 , m 3 − m 2 m_1,m_2-m_1,m_3-m_2 m1,m2m1,m3m2 必然也互质,所以 g c d ( x , y − x , z − y ) = a = g c d ( x , y , z ) gcd(x,y-x,z-y)=a=gcd(x,y,z) gcd(x,yx,zy)=a=gcd(x,y,z)

那么,知道了这个之后又有什么用呢

我们可以用差分的思想,把原数组变为 a 1 , a 2 − a 1 , a 3 − a 2 , … , a n − a n − 1 a_1,a_2-a_1,a_3-a_2,\dots ,a_n-a_{n-1} a1,a2a1,a3a2,,anan1(用 s u m i sum_i sumi 表示 a i − a i − 1 a_i-a_{i-1} aiai1

这样的话,修改就好办了,直接在 s u m l sum_l suml d d d,在 s u m r + 1 sum_{r+1} sumr+1 d d d(中间的数加的 d d d 相互抵消了)

查询的时候,根据辗转相减法,先找出 g c d ( s u m l + 1 , s u m l + 2 , … , s u m r ) gcd(sum_{l+1},sum_{l+2},\dots ,sum_{r}) gcd(suml+1,suml+2,,sumr),由于此时 s u m l sum_{l} suml 记录的是 a l − a l − 1 a_{l}-a_{l-1} alal1,要单独处理一下,而不难看出 s u m 1 + s u m 2 + ⋯ + s u m l = a l sum_1+sum_2+\dots +sum_l=a_l sum1+sum2++suml=al,所以答案为

a n s = g c d ( ∑ i = 1 l s u m i , g c d ( s u m l + 1 , s u m l + 2 , … , s u m r ) ) ans=gcd(\sum^{l}_{i=1}sum_i,gcd(sum_{l+1},sum_{l+2},\dots,sum_r)) ans=gcd(i=1lsumi,gcd(suml+1,suml+2,,sumr))

因此,用一个树状数组记录 s u m sum sum 的前缀和,用一个线段树记录 s u m sum sum 的区间 g c d gcd gcd 就可以了


【代码】

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500005
#define ll long long
#define lowbit(x) x&-x
using namespace std;
int n,m;
ll a[N],bit[N],Gcd[N<<2];
void add(int i,ll x)
{
	while(i<=n)
	{
		bit[i]+=x;
		i+=lowbit(i);
	}
}
ll sum(int i)
{
	ll ans=0;
	while(i)
	{
		ans+=bit[i];
		i-=lowbit(i);
	}
	return ans;
}
void build(int root,int l,int r)
{
	if(l==r)
	{
		Gcd[root]=a[l]-a[l-1];
		return;
	}
	int mid=(l+r)>>1;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
	Gcd[root]=__gcd(Gcd[root<<1],Gcd[root<<1|1]);
}
void modify(int root,int l,int r,int x,ll k)
{
	if(l==r)
	{
		Gcd[root]+=k;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)  modify(root<<1,l,mid,x,k);
	else  modify(root<<1|1,mid+1,r,x,k);
	Gcd[root]=__gcd(Gcd[root<<1],Gcd[root<<1|1]);
}
ll query(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	  return Gcd[root];
	int mid=(l+r)>>1;
	if(y<=mid)  return query(root<<1,l,mid,x,y);
	if(x>mid)  return query(root<<1|1,mid+1,r,x,y);
	return __gcd(query(root<<1,l,mid,x,y),query(root<<1|1,mid+1,r,x,y));
}
int main()
{
	int x,y,i;  ll k;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	  scanf("%lld",&a[i]);
	build(1,1,n);
	for(i=1;i<=m;++i)
	{
		char c;  cin>>c;
		scanf("%d%d",&x,&y);
		if(c=='C')
		{
			scanf("%lld",&k);
			add(x,k),modify(1,1,n,x,k);
			if(y<n)add(y+1,-k),modify(1,1,n,y+1,-k);
		}
		else  printf("%lld\n",abs(__gcd(a[x]+sum(x),query(1,1,n,x+1,y))));
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值