Interval GCD

题面描述

给定一个长度为N的数列A,以及M条指令 (N≤5*10^5, M<=10^5),每条指令可能是以下两种之一: “C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。 “Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

输入格式

第一行两个整数N,M,第二行N个整数Ai,接下来M行每条指令的格式如题目描述所示。

输出格式

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

样例

一看这个数据范围我们就可以得知一件事情,一定要用longlong,细节一定要注意,这个题还是比较鬼畜的,还是比较难想的,但是我们可以想到可以对序列进行一个差分的操作,然后可以单点修改就可以成为区间修改,因为差分序列的前缀和是原序列,直接在差分序列上的x+d,y+1的地方-d,最后前缀和序列就是x……y加了d,我们可以用树状数组维护一下。b[i]=a[i]-a[i-1];这样到最后Q l r就相当于是gcd(a[l],ask(1,l+1,r));然后就可以上去搞了,一顿瞎搞即可

代码

#include<bits/stdc++.h>
using namespace std;
struct hf
{
	long long l,r;
	long long dat;
}t[4000010];
long long a[2010000],c[2010000],b[2010000],n,m;
long long gcd(long long q,long long p)
{
	if(p==0)
	return q;
	return gcd(p,q%p);
}
void build(long long p,long long l,long long r)
{
	t[p].l=l,t[p].r=r;
	if(l==r)
	{
		t[p].dat=a[l];
		return ;
	}
	long long mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	t[p].dat=gcd(t[p*2].dat,t[p*2+1].dat);
}
void change(long long p,long long x,long long v)
{
	if(t[p].l==t[p].r)
	{
		t[p].dat+=v;
		return;
	}
	long long mid=(t[p].l+t[p].r)/2;
	if(x<=mid)
	change(p*2,x,v);
	else
	change(p*2+1,x,v);
	t[p].dat=gcd(t[p*2].dat,t[p*2+1].dat);
}
long long ask(long long p,long long l,long long r)
{
	if(t[p].l>=l&&t[p].r<=r)
	{
		return abs(t[p].dat);
	}
	long long v=0;
	long long mid=(t[p].l+t[p].r)/2;
	if(l<=mid)
	v=gcd(v,ask(p*2,l,r));
	if(r>mid)
	v=gcd(v,ask(p*2+1,l,r));
	return abs(v);
}
void add(long long x,long long d)
{
	for(;x<=n;x+=x&-x)
	b[x]+=d;
}
long long find(long long x)
{
	long long ans=0;
	for(;x;x-=x&-x)
	ans+=b[x];
	return ans;
}
int main()
{
	freopen("test.in","r",stdin);
  freopen("test.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%lld",&c[i]);
	for(int i=1;i<=n;i++)
	a[i]=c[i]-c[i-1];
	build(1,1,n);
	for(int j=1;j<=m;j++)
	{
		char op[2];
		long long x,y,z;
		scanf("%s",op );
		scanf("%lld%lld",&x,&y);
		if(op[0]=='Q')
		{
			//cout<<c[x]<<' '<<find(x)<<' '<<ask(1,x+1,y)<<endl;
			printf("%lld\n",gcd(c[x]+find(x),ask(1,x+1,y)));
		}
		else
		{
			scanf("%lld",&z);
			add(x,z);
			change(1,x,z);
			add(y+1,-z);
			change(1,y+1,-z);
		}
	}
 } 

留下评论

通过 WordPress.com 设计一个这样的站点
从这里开始