小Z的加油店 HYSBZ - 5028 線段樹+數學

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章