小Z经营一家加油店。小Z加油的方式非常奇怪。他有一排瓶子,每个瓶子有一个容量vi。每次别人来加油,他会让
别人选连续一段的瓶子。他可以用这些瓶子装汽油,但他只有三种操作:
1.把一个瓶子完全加满;
2.把一个瓶子完全倒空;
3.把一个瓶子里的汽油倒进另一个瓶子,直到倒出瓶子空了或者倒进的瓶子满了。
当然,为了回馈用户,小Z会时不时选择连续一段瓶子,给每个瓶子容积都增加x。
为了尽可能给更多的人加油,每次客户来加油他都想知道他能够倒腾出的汽油量最少是多少?
当然他不会一点汽油都不给客户。
Input
第一行包括两个数字:瓶子数n,事件数m。
第二行包含n个整数,表示每个瓶子的容量vi。
接下来m行,每行先有三个整数fi li ri。
若fi=1表示询问li到ri他最少能倒腾出的汽油量最少是多少?
若fi=2 再读入一个整数x。表示他将li到ri的瓶子容量都增加了x。
1 <= n,m <= 10^5 , 1<=li<=ri<=n , 1<=初始容量,增加的容量<=1000
Output
对于每个询问输出对应的答案
Sample Input
3 4 2 3 4 1 1 3 2 2 2 1 1 1 3 1 2 3
Sample Output
1 2 4
Hint
有可能出现L>R,读入的p不只有0和1,把所有非1操作当成2才能AC
题意:
询问
1:求[L,R]的GCD
2:区间[L,R]的值加x
思路:公式:gcd(a,b,c,d.......)=gcd(a,b-a,c-b,d-c........)。我们维护一个差序列:a,b-a,c-b,d-c..... 。例如序列a,b,c,d.....对这个区间全加val,那么差序列为a+val,b-a,c-b,d-c.....那么问题就变得简单了,就变成了点更新区间查询了。
例如:我们要求[b,d]区间的gcd,我们先查询差序列[1,b]的前缀和,为什么呢?差序列是这样的:a,b-a,c-b,d-c..... [1,b]的前缀和为a+b-a=b,即求[1,b]的前缀和与差序列[c,d]的gcd的gcd。
//这个题为啥LR设成参数就A,放在结构体里就RE啊。。。。。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int a[maxn],n,m;
struct node{
int l;
int r;
int sum;
int gcd;
}tree[maxn<<2];
void pushup(int cur)
{
tree[cur].sum=tree[cur<<1].sum+tree[cur<<1|1].sum;
tree[cur].gcd=__gcd(tree[cur<<1].gcd,tree[cur<<1|1].gcd);
}
void build(int cur,int l,int r)
{
tree[cur].l=l;
tree[cur].r=r;
if(l==r)
{
tree[cur].gcd=a[l];
tree[cur].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(cur<<1,l,mid);
build(cur<<1|1,mid+1,r);
pushup(cur);
}
void update(int cur,int x,int y)
{
if(tree[cur].l==tree[cur].r)
{
tree[cur].sum+=y;
tree[cur].gcd+=y;
return;
}
if (x<=tree[cur<<1].r) update(cur<<1,x,y);
else update(cur<<1|1,x,y);
pushup(cur);
}
int query(int d,int l,int r,int x,int y)
{
if (x<=l&&r<=y) return tree[d].gcd;
int mid=(l+r)/2;
int res=0;
if (x<=mid) res=__gcd(res,query(d*2,l,mid,x,y));
if (y>mid) res=__gcd(res,query(d*2+1,mid+1,r,x,y));
return res;
}
int find(int d,int l,int r,int x,int y)
{
if (x<=l&&r<=y) return tree[d].sum;
int mid=(l+r)/2;
int res=0;
if (x<=mid) res+=find(d*2,l,mid,x,y);
if (y>mid) res+=find(d*2+1,mid+1,r,x,y);
return res;
}
int main()
{
int op,l,r,x;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=n;i>1;i--) a[i]-=a[i-1];
build(1,1,n);
while (m--)
{
scanf("%d%d%d",&op,&l,&r);
if(l>r) swap(l,r);
if (op==1) printf("%d\n",abs(__gcd(query(1,1,n,l+1,r),find(1,1,n,1,l))));
else
{
scanf("%d",&x);
update(1,l,x);
if (r+1<=n) update(1,r+1,-x);
}
}
return 0;
}