操作格子(线段树)

11 篇文章 1 订阅
5 篇文章 0 订阅

问题描述
有n个格子,从左到右放成一排,编号为1-n。

共有m次操作,有3种操作类型:

1.修改一个格子的权值,

2.求连续一段格子权值和,

3.求连续一段格子的最大值。

对于每个2、3操作输出你所求出的结果。

输入格式
第一行2个整数n,m。

接下来一行n个整数表示n个格子的初始权值。

接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。

输出格式
有若干行,行数等于p=2或3的操作总数。

每行1个整数,对应了每个p=2或3操作的结果。

样例输入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。

对于50%的数据n <= 5000,m <= 5000。

对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。

这次多了一个特性,就是多求了一个区间段的最大值,不分析了。
代码:

import java.util.Scanner;
class  P//因为一个线段点不仅需要保存和值还要保存最大值,所以设了两个域值
{
    int sum;
    int max;
    P(int sum,int max)
    {
        this.sum=sum;
        this.max=max;
    }
    P(){}
}
public class Main 
{   
    static P T[];
    static Scanner sc;
    public static void main(String[] args) 
    {
        sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        T=new P[n<<2];
        buildUp(1,1,n);//建树
        int x[]=new int[3];
        while((m--)>0)
        {
            for(int i=0;i<3;i++)
                x[i]=sc.nextInt();
            if(x[0]==1)
                change(x[1],x[2],1,1,n);
            else
                if(x[0]==2)
                    System.out.println(querySum(x[1],x[2],1,1,n));
                else
                    System.out.println(queryMax(x[1],x[2],1,1,n));
        }
    }
    static void buildUp(int s,int l,int r)
    {
        if(l==r)
        {
            int a=sc.nextInt();
            T[s]=new P(a,a);
            return;
        }
        int m=(l+r)>>1;
        buildUp(s<<1,l,m);
        buildUp(s<<1|1,m+1,r);
        T[s]=new P();
        T[s].sum=T[s<<1].sum+T[s<<1|1].sum;
        T[s].max=Math.max(T[s<<1].max, T[s<<1|1].max);//只是多了这行而已
    }
    static void change(int p,int c,int s,int l,int r)
    {
        if(l==r&&l==p)
        {
            T[s].max=c;
            T[s].sum=c;
            return;
        }
        int m=(l+r)>>1;
        if(p<=m)
            change(p,c,s<<1,l,m);
        else
            change(p,c,s<<1|1,m+1,r);
        T[s].sum=T[s<<1].sum+T[s<<1|1].sum;
        T[s].max=Math.max(T[s<<1].max, T[s<<1|1].max);//同样的和值和最大值都要变

    }
    static int querySum(int L,int R,int s,int l,int r)
    {
        if(L<=l&&r<=R)return T[s].sum;

        int m=(l+r)>>1;
        int ans=0;
        if(m>=L)
            ans+=querySum(L,R,s<<1,l,m);
        if(m<R)
            ans+=querySum(L,R,s<<1|1,m+1,r);
        return ans;//这里没变化
    }
    static int queryMax(int L,int R,int s,int l,int r)
    {
        if(L<=l&&r<=R)return T[s].max;
        int m=(l+r)>>1;
        if(R<=m)
            return queryMax(L,R,s<<1,l,m);//进一步去缩小范围
        if(m<L)
            return queryMax(L,R,s<<1|1,m+1,r);
        return Math.max(queryMax(L,R,s<<1,l,m), queryMax(L,R,s<<1|1,m+1,r));//如果m夹杂在R和L之间,那么我们就取他们的最大值,与求和函数还是有区别的
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值