牛客小白月赛16

链接:https://ac.nowcoder.com/acm/contest/949/H
来源:牛客网

题目描述

小阳手中一共有 n 个贝壳,每个贝壳都有颜色,且初始第 i 个贝壳的颜色为 coli i​ 。现在小阳有 3 种操作:

1 l r x:给 [l,r] 区间里所有贝壳的颜色值加上 xxx 。

2 l r:询问 [l,r] 区间里所有相邻贝壳 颜色值的差(取绝对值) 的最大值(若 l=rl = rl=r 输出 0)。

3 l r :询问 [l,r] 区间里所有贝壳颜色值的最大公约数。

输入描述:

第一行输入两个正整数 n,mn,mn,m,分别表示贝壳个数和操作个数。
第二行输入 nnn 个数 colicol_icoli​,表示每个贝壳的初始颜色。
第三到第 m+2m + 2m+2 行,每行第一个数为 optoptopt,表示操作编号。接下来的输入的变量与操作编号对应。
输出描述:
共 m 行,对于每个询问(操作 2 和操作 3)输出对应的结果。
示例1
输入
5 6
2 2 3 3 3
1 2 3 3
2 2 4
3 3 5
1 1 4 2
3 2 3
2 3 5
输出
3
3
1
3
备注:
1≤n,m≤100000

1≤coli≤1000

1≤opt≤3,1≤l≤r≤n

题目大意:

线段树操作集合问题,我们发现有三种操作,第一种 区间更新,l-r 区间每个数的值 +x 第二种 相邻最大值,即区间各数之间相邻的最大值的绝对值,第三种,求区间的gcd。

解题思路:

第一次碰到这种问题,往常的区间更新都是借用一个lazy数组来完成,但考虑到这个题还有相邻之间的距离最大值,还有区间gcd,显然用lazy肯定不行,通过这个题我学到了差分数组的思想。
差分数组:即数组中存放的不是原来的值,而是当前的数和前一个数的差值:
举个例子: 原数组 1 3 5 10 8 ——> 差分数组 1 2 2 5 -2
我们还可以发现一个规律,对差分数组求前缀和就是原来的第n项。
不难发现,差分数组的值就是相邻之间的差值,所以可以用线段树维护差分数组的绝对值的最大值。
关于区间更新:在差分数组中可以这样实现,举个例子:【3,5】这个区间内的每一个数都+2,因为差分数组中存放的是一个差值,所以我们在3这个位置+2,在6这个位置-2 就可以实现【3,5】每个数都+2了(可以自己带一组数据试试)。
再谈gcd问题 gcd(a,b)= gcd(a,b-a)同样可以用差分数组来实现,所以其他的不变,只需要把原来建树的普通数组改成差分数组即可,其他操作都用线段树来实现。AC代码:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int _max = 1e5+50;
int a[_max];
struct node//线段树中存放的值
{
    int sum,mx,gd;
}tree[_max<<2];
int gcd(int a,int b)//欧几里得求gcd
{
    return b==0?a:gcd(b,a%b);
}
void pushup(int k)//线段树常规更新函数
{
    tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx);
    tree[k].gd=gcd(tree[k<<1].gd,tree[k<<1|1].gd);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void build(int node,int l,int r)
{
    if(l==r)
    {
        tree[node].mx=abs(a[l]);//因为要求的是绝对值,所以这里维护一下绝对值。
        tree[node].gd=abs(a[l]);//gcd同样存一下绝对值
        tree[node].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    pushup(node);
}
void update(int node,int l,int r,int idx,int val)//区间更新
{
    if(l==r)
    {
        tree[node].sum+=val;
        tree[node].mx=tree[node].gd=abs(tree[node].sum);
        return;
    }
    int mid=(l+r)>>1;
    if(idx<=mid)
      update(node<<1,l,mid,idx,val);
    else
      update(node<<1|1,mid+1,r,idx,val);
    pushup(node);
}
int query_sum(int node,int l,int r,int start,int end)//区间求和,维护一下L==R的情况
{
    if(l>=start&&r<=end)
      return tree[node].sum;
    int mid=(l+r)>>1;
    int ans=0;
    if(start<=mid)
      ans+=query_sum(node<<1,l,mid,start,end);
    if(end>mid)
      ans+=query_sum(node<<1|1,mid+1,r,start,end);
    return ans;  
}
int query_max(int node,int l,int r,int start,int end)//区间最大值
{
    if(l>=start&&r<=end)
      return tree[node].mx;
    int mid=(l+r)>>1;
    int ans=-1;
    if(start<=mid)
      ans=max(query_max(node<<1,l,mid,start,end),ans);
    if(end>mid)
      ans=max(query_max(node<<1|1,mid+1,r,start,end),ans);
    return ans;
}
int query_gcd(int node,int l,int r,int start,int end)//区间gcd
{
    if(l>=start&&r<=end)
      return tree[node].gd;
    int mid=(l+r)>>1;
    int ans=0;
    if(start<=mid)
      ans=gcd(query_gcd(node<<1,l,mid,start,end),ans);
    if(end>mid)
      ans=gcd(query_gcd(node<<1|1,mid+1,r,start,end),ans);
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
      cin>>a[i];
    a[0]=0;
    for(int i=n;i>=1;i--)
      a[i]-=a[i-1];
    build(1,1,n);
    while(m--)
    {
        int op,l,r;
        cin>>op>>l>>r;
        if(op==1)
        {
            int x;
            cin>>x;
            update(1,1,n,l,x);//l  +x    r+1  -x
            if(r<n)
              update(1,1,n,r+1,-x);
        }
        else if(op==2)
        {
            if(l==r)
              cout<<0<<endl;
            else
            {
                int ans=query_max(1,1,n,l+1,r);
                cout<<ans<<endl;
            }
        }
        else
        {
            int ans=abs(query_sum(1,1,n,1,l));
            if(l==r)
               cout<<ans<<endl;
            else
            {
                ans=gcd(ans,query_gcd(1,1,n,l+1,r));
                cout<<ans<<endl;
            }
        }
    }
    //system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/Hayasaka/p/14294265.html