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

 

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