小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;
}