zoukankan      html  css  js  c++  java
  • 牛客-小阳的贝壳(线段树集合操作)

    https://ac.nowcoder.com/acm/contest/949/H

    题目描述

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

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

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

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

    输入描述:

    第一行输入两个正整数 n,m,分别表示贝壳个数和操作个数。
    第二行输入 n 个数 coli,表示每个贝壳的初始颜色。
    第三到第 m+2 行,每行第一个数为 op,表示操作编号。接下来的输入的变量与操作编号对应。

    输出描述:

    共 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

    备注:

    1n,m105,1coli,x103,1opt3,1lrn

    这道题就是一道很基本的线段树的题目,但基本上把线段树的基础各种操作都放进去了。
    我们知道,线段树维护和统计的东西要满足区间加法,而其中就包括了以下三个:

    数字之和——总数字之和 = 左区间数字之和 + 右区间数字之和

    最大公因数(GCD)——总GCD = gcd( 左区间GCD , 右区间GCD );

    最大值——总最大值=max(左区间最大值,右区间最大值)

    而这题全都包含了,所以可以当做一个比较好的板子。

    以下是代码。

    其中 __gcd 是c++库里的一个函数,跟手动gcd求最大公约数一样。

    而求区间所有数的最大公约数的方法:

    gcd(a,b)=gcd(a,ba) 
    gcd(a,b,c)=gcd(a,ba,cb) 
    gcd(a1,a2,,an)=gcd(a1,a2a1,a3a2,,anan1) 
     
    所以在这里我们建树的时候存的是原数列的差分序列,从而来维护最大公约数。
     
    //https://ac.nowcoder.com/acm/contest/949/H
    #include<bits/stdc++.h>
    using namespace std;
    const int N=100005;
    #define ls rt<<1
    #define rs rt<<1|1
    int a[N],Max[N<<2],Sum[N<<2],Gcd[N<<2];
    void push_up(int rt){
        Max[rt]=max(Max[ls],Max[rs]);
        Sum[rt]=Sum[ls]+Sum[rs];
        Gcd[rt]=__gcd(Gcd[ls],Gcd[rs]);
    }
    void build(int l,int r,int rt){
        if(l==r){
            Sum[rt]=a[l];
            Max[rt]=Gcd[rt]=abs(a[l]); //一开始每个节点存的是其差分绝对值
            return ;
        }
        int m=(l+r)>>1;
        build(l,m,ls);
        build(m+1,r,rs);
        push_up(rt);
    }
    void update(int p,int add,int l,int r,int rt){
        if(l==r){
            a[l]+=add;
            Sum[rt]=a[l];
            Max[rt]=Gcd[rt]=max(a[l],-a[l]);
            return ;
        }
        int m=(l+r)>>1;
        if(p<=m) update(p,add,l,m,ls);
        else update(p,add,m+1,r,rs);
        push_up(rt);
    }
    int query_max(int L,int R,int l,int r,int rt){
        if(L<=l&&R>=r) return abs(Max[rt]); //查询最大值
        int ans=0;
        int m=(l+r)>>1;
        if(L<=m) ans=max(ans,query_max(L,R,l,m,ls));
        if(R>m) ans=max(ans,query_max(L,R,m+1,r,rs));
        return ans;
    }
    int query_sum(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R) return Sum[rt];
        int ans=0,mid=(l+r)>>1;
        if(L<=mid) ans+=query_sum(L,R,l,mid,ls);
        if(R>mid) ans+=query_sum(L,R,mid+1,r,rs);
        return ans;
    }
    int query_gcd(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R) return Gcd[rt];
        int ans=0,mid=(l+r)>>1;
        if(L<=mid) ans=__gcd(ans,query_gcd(L,R,l,mid,ls));
        if(R>mid) ans=__gcd(ans,query_gcd(L,R,mid+1,r,rs));
        return ans;
    }
    int main(int argc, char * argv[]) 
    {
        std::ios::sync_with_stdio(false);
        int n,q,op,l,r,x;
        cin>>n>>q;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=n;i;i--) a[i]-=a[i-1]; //存差值来求最大公约数
        build(1,n,1);
        while(q--){
            cin>>op>>l>>r;
            if(op==1){
                cin>>x;
                update(l,x,1,n,1);
                if(r<n) update(r+1,-x,1,n,1);
            }
            else if(op==2){
                if(l==r) cout<<0<<endl;
                else cout<<query_max(l+1,r,1,n,1)<<endl;
            }
            else{
                int t=abs(query_sum(1,l,1,n,1));
                if(l==r) cout<<t<<endl;
                else cout<<__gcd(t,query_gcd(l+1,r,1,n,1))<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    Python面向对象(类的成员之属性)
    Python面向对象(类的成员之方法)
    Python面向对象(类的成员之字段)
    Python面向对象(多态)
    Python面向对象(继承)
    Python面向对象(构造方法)
    Python面向对象(self参数、封装)
    Python面向对象(定义类和创建对象)
    Pangolin库的使用
    Combinations
  • 原文地址:https://www.cnblogs.com/wushengyang/p/11192089.html
Copyright © 2011-2022 走看看