首页 > 其他分享 >Interval GCD 题解

Interval GCD 题解

时间:2024-03-09 17:46:57浏览次数:26  
标签:GCD read 题解 Interval large int ls optimize gcd

题目描述

给定一个长度为 \(\large n\) 的数组 \(\large a\),以及 \(\large m\) 条指令 (\(n\leq5\times10^5,m\leq10^5\)),每条指令可能是以下两种之一:

“\(\large\operatorname{C\ l\ r\ d}\)”,表示把 \(\large a[l],a[l+1],…,a[r]\) 都加上 \(\large d\)。

“\(\large\operatorname{Q\ l\ r}\)”,表示询问 \(\large a[l],a[l+1],…,a[r]\) 的 \(\large \gcd\)。


Solve

1.引理

更相减损术 \(\large\gcd(a,b)=\gcd(a,a-b)\) 可利用数学归纳法扩展至 \(\large\gcd(a_1,a_2,\cdots,a_n)=\gcd(a_1,a_2-a_1,a_3-a_2,\cdots,a_n-a_{n-1})\)

2.思路

考虑利用差分将区间修改转化为单点修改,用线段树维护区间 \(\large\gcd\),然后用树状数组维护前缀和以求出 \(\large a_i\) 的真实值(也可以用线段树维护)。

3.Code

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
#define int long long
inline int read()
{
	short f=1;
	int x=0;
	char c=getchar();
	while(c<'0'||c>'9')	{if(c=='-')	f=-1;c=getchar();}
	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
struct seg
{
	int dat,l,r;
	#define mid (t[p].l+t[p].r>>1)
	#define ls (p<<1)
	#define rs (p<<1|1)
	#define len(p)	(t[p].r-t[p].l+1)
}t[2000010];
int gcd(int x,int y)
{
	x=abs(x);y=abs(y);//考虑负数
	if(x<y)	swap(x,y);
	if(!y)	return x;//在query中res=0,即y=0,此时直接返回x
	return x%y?gcd(y,x%y):y;
}
int n,m,a[500010],c[500010],l,r,d;
char op;
inline void upd(int p)
{
	t[p].dat=gcd(t[ls].dat,t[rs].dat);
}
void build(int p,int l,int r)
{
	t[p].l=l;t[p].r=r;
	if(l==r)
	{
		t[p].dat=a[l]-a[l-1];
		return;
	}
	build(ls,l,mid);
	build(rs,-~mid,r);
	upd(p);
}
void change(int p,int pos,int d)
{
	if(t[p].l==t[p].r)
	{
		t[p].dat+=d;
		return;
	}
	if(mid>=pos)	change(ls,pos,d);
	if(mid<pos)	change(rs,pos,d);
	upd(p);
}
int query(int p,int l,int r)
{
	if(t[p].l>=l&&t[p].r<=r)	return t[p].dat;
	int res=0;
	if(mid>=l)	res=gcd(res,query(ls,l,r));
	if(mid<r)	res=gcd(res,query(rs,l,r));
	return res;
}
inline void add(int x,int y)	{for(;x<=n;x+=x&-x)	c[x]+=y;}
inline int ask(int x)	{int res=0;for(;x;x-=x&-x)	res+=c[x];return res;}
void print(int p)
{
	if(t[p].l==t[p].r)
	{
		printf("%lld ",t[p].dat);
		return;
	}
	print(ls);print(rs);
}
signed main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i=-~i)
		a[i]=read(),add(i,a[i]-a[i-1]);
	build(1,1,n);
	for(int i=1;i<=m;i=-~i)
	{
		cin>>op;
		l=read();r=read();
		if(op=='Q')
			printf("%lld\n",gcd(ask(l)/*a[l]的真实值*/,query(1,-~l,r)/*gcd(a[l+1]~a[r])*/));
		else
		{
			d=read();add(l,d);add(-~r,-d),
			change(1,l,d);
			if(r<n)	change(1,-~r,-d);//注意r=n的情况,change会越界导致bug
		}
	}
	return 0;
}

标签:GCD,read,题解,Interval,large,int,ls,optimize,gcd
From: https://www.cnblogs.com/sorato/p/18063030

相关文章

  • CF1264D2 Beautiful Bracket Sequence (hard version) 题解
    括号深度的本质,其实就是删除若干个字符以后使得左边一半全是(,右边一半全是),最终(的个数的最大值。那么就一定存在一个位置使得在这个位置以及之前的字符中(的个数等于这个字符后)的个数。考虑枚举这个位置,记它左边的(的个数为\(a\)、?的个数为\(x\),右边的)的个数......
  • [CF696B] Puzzles 题解
    首先很好想到要用树形\(dp\)。然后设\(dp_i\)为遍历到第\(i\)个点的期望时间,\(sz_i\)代表\(i\)的子树大小。发现有转移方程:\[dp_i=dp_{fa_i}+1+\sum\limits_{j\infa_i且j\nei}sz_j\timesq\]其中\(q\)为一个常数,代表在排列中\(j\)在\(i\)前的概率。很容易发......
  • 无聊的数列[题解]
    无聊的数列[link1][link2]题目大意给定一个数列\(A\)有两种操作:将数列中\(A_i\)(\(L\leqi\leqR\))加上一个等差数列(首项D公差K)查询数列中第P位数区间加上一个等差数列可以用差分来解决例原序列:000000差分序列:000000等差序列:13579(首项1......
  • 课堂练习 最大值 原题链接+题解
    题目可以去我的洛谷题库看:https://www.luogu.com.cn/problem/U412348(带数据,真难出)题解考虑两种解题方式。由于题目范围较小,可以check+暴力,如果范围大一点,可以check+二分答案。先讲check函数,小学四年级数学书说了,这种问题也被它叫做“铺地砖”问题,计算剪出的正方形数量的方......
  • 一本通 1270 混合背包 题解
    是在hydro上做的,墙裂推荐hydro的一本通题库!链接是:https://hydro.ac/d/ybttk/p/T1270。分析一下,可以分类讨论,处理的时候,零一背包(\(p_i=1\))一个,完全背包(\(p_i=0\))一个,多重背包(\(p_i>1\))一个,状态转移方程不用列的,直接去抄模板就可以啦~代码是这样的捏:#include<bits/st......
  • P6583 回首过去 题解
    P6583回首过去题解题目传送门好题。更新(2023-12-05):把代码和$\LaTeX$改得更好看了。题意简述给定正整数$n$,求出有序整数对$(x,y)$的个数,满足$1\lex,y\len$且$\dfracxy$可以表示为十进制有限小数。$1\len\le10^{12}$。前置知识数论分块解法Subtas......
  • CF1846D Rudolph and Christmas Tree 题解
    因为\(n\)个三角形有重叠部分,所以我们可以倒序处理每个三角形,并对其进行分类讨论:若当前三角形编号为\(n\),则直接将总面积加上\(\dfrac{d\timesh}{2}\)。否则,再次分出两种情况:若当前三角形的\(y_i+h>y_{i+1}\)(即编号为\(i,i+1\)的三角形有重叠),则如下图所示:......
  • CF387B George and Round 题解
    考虑采用双指针法解决此题。首先需要对\(a,b\)数组排序,并且维护两个指针\(l,r\),分别指向\(a,b\)两个数组中的元素。接着循环移动\(r\)指针,每次都尝试匹配\(a_l\)和\(b_r\):若\(a_l\leb_r\),则说明\(a_l=b_r\)或可以采用减少\(b_r\)的方式使\(a_l=b_r\),这......
  • P3670 [USACO17OPEN] Bovine Genomics S 题解
    题意给定\(2\)组字符串,每组\(n\)个,每个字符串包含\(m\)个字符。我们称一个三元组\((i,j,k)\)是合法的,当且仅当第二组的每个字符串中下标为\((i,j,k)\)的字符拼成的字符串与第一组的每个字符串中下标为\((i,j,k)\)的字符拼成的字符串均不相等。现在需要你对于给定的......
  • CF99B Help Chef Gerasim 题解
    分别对三种情况进行分类讨论。第一种情况:显然,若\(\sum^{n}_{i=1}a_i\bmodn\neq0\),则输出\(\texttt{Unrecoverableconfiguration.}\);同时,我们遍历\(a_{1\simn}\),若存在两个以上的\(a_i\)满足\(a_i\neq\sum^{n}_{i=1}a_i\divn\),则也输出\(\texttt{Unreco......