蓝桥杯——操作格子(线段树)

问题描述

有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

数据规模与约定

对于20%的数据n <= 100,m <= 200。

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

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

 

方法一(不适用数据太大的情况,容易超时)

import java.util.Scanner;

public class Main3

{  

final static int MAX_N = 400010; //定义一个静态的最大值

public static void main(String args[])

{  

Scanner sc=new Scanner(System.in);

int n=sc.nextInt();

int m=sc.nextInt();

Main3 a=new Main3();//调用非静态方法需要先创建一个对象

a.Build(1,1,n); //构建一个从1到n的线段树

int value;//每个格子的权值

for(int i=1;i<=n;i++)

{

value=sc.nextInt();

a.Insert(1,i,value);  //向已有线段数中插入权值



}



while(m!=0)

{

   int p=sc.nextInt();

   int x=sc.nextInt();

   int y=sc.nextInt();

   

   switch(p)

   {

   case 1:a.Update(1,x,y);break;  //修改格子x的权值为y;

   case 2:System.out.println(a.Qsum(1,x,y));break;  //求区间[x,y]内的权值和

   case 3:System.out.println(a.Qmax(1,x,y));break;  //求区间[x,y]内格子的最大权值

   }

m--;



}

}



class Node   //构建一个线段树的结点的类

{

int left,right;  //区间[left,right]

int sum, max; //sum为区间[left,right]权值和,max为区间的最大值

Node () {}

Node (int _l, int _r, int _s, int _m) {

left = _l;

right = _r;

sum = _s;

max = _m;

}

}

Node tree[] = new Node[MAX_N];//定义线段树结点的空间





  void Build(int i,int left,int right)//i为数组下标,称作结点序号,为区间[left,right]建立一个以i为祖先的线段树

{

  tree[i] = new Node(left, right, 0, 0);

if(left==right)

return ;

Build(i*2,left,(left+right)/2); //构建left至(left+right)/2的左孩子;

Build(i*2+1,(left+right)/2+1,right);//构建右孩子;

}



  void Insert(int i,int n,int value)  //为线段树插入一个值

  {

  tree[i].sum+=value;   //区间的权值和

  if(tree[i].max<value)

  tree[i].max=value;  //最大值

  if(tree[i].left==tree[i].right)  //左右边距相等不再插入新值

  return ;

  if(n<=(tree[i].left+tree[i].right)/2)

  Insert(i*2,n,value);  //更新左孩子

  else

  Insert(i*2+1,n,value);  //更新右孩子

  

  }

  

  void Update(int i,int n,int value) 

  {

  if(n==tree[i].left && n==tree[i].right)  //下标与左右范围相等,存本数

  {

  tree[i].sum=value;

  tree[i].max=value;

  return;

  }

  int mid=(tree[i].left+tree[i].right)/2;

  if(n<=mid)

  Update(i*2,n,value);

  else

  Update(i*2+1,n,value);

  

  tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; //更新总和

  tree[i].max=Math.max(tree[i*2].max,tree[i*2+1].max);  //更新最大值

  }

  

  int Qsum(int i,int left,int right)  //求权值和

  {

  if(left==tree[i].left && right==tree[i].right)

  return tree[i].sum;

  int mid=(tree[i].left+tree[i].right)/2;

  if(right<=mid)

  return Qsum(i*2,left,right);

  else if(left>mid)

  return Qsum(i*2+1,left,right);

  else return Qsum(i*2,left,mid)+Qsum(i*2+1,mid+1,right);//若范围在左右孩子之间,分别求总和  

  }

  int Qmax(int i,int left,int right)

  {

  if(left==tree[i].left && right==tree[i].right)

  return tree[i].max;

  int mid=(tree[i].left+tree[i].right)/2;

  if(right<=mid)

  return Qmax(i*2,left,right);

  else if(left>mid)

  return Qmax(i*2+1,left,right);

  else return   Math.max(Qmax(i*2,left,mid), Qmax(i*2+1,mid+1,right));   

  }

}




 

方法二(适用于大数据)

import java.io.*;

import java.util.*;

public class Main2{



final static int MAX_N = 400010;



class Node   

{

int left,right;  

int sum, max; 

Node () {}

Node (int _l, int _r, int _s, int _m) {

left = _l;

right = _r;

sum = _s;

max = _m;

}

}



int n, m;

Node tree[] = new Node[MAX_N];

int a[] = new int[MAX_N];



void up(int id) {

tree[id].sum = tree[id*2].sum + tree[id*2+1].sum;

tree[id].max = Math.max(tree[id*2].max, tree[id*2+1].max);

}



void Build(int i,int left,int right)

{

  tree[i] = new Node(left, right, 0, 0);

if(left==right)

return ;

Build(i*2,left,(left+right)/2); 

Build(i*2+1,(left+right)/2+1,right);

}



void Insert(int i,int n,int value)  

  {

  tree[i].sum+=value;  

  if(tree[i].max<value)

  tree[i].max=value;  

  if(tree[i].left==tree[i].right) 

  return ;

  if(n<=(tree[i].left+tree[i].right)/2)

  Insert(i*2,n,value); 

  else

  Insert(i*2+1,n,value);  

  

  }

void Update(int i,int n,int value) 

  {

  if(n==tree[i].left && n==tree[i].right)  

  {

  tree[i].sum=value;

  tree[i].max=value;

  return;

  }

  int mid=(tree[i].left+tree[i].right)/2;

  if(n<=mid)

  Update(i*2,n,value);

  else

  Update(i*2+1,n,value);

  

  tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; 

  tree[i].max=Math.max(tree[i*2].max,tree[i*2+1].max); 

  }



 int Qsum(int i,int left,int right) 

  {

  if(left==tree[i].left && right==tree[i].right)

  return tree[i].sum;

  int mid=(tree[i].left+tree[i].right)/2;

  if(right<=mid)

  return Qsum(i*2,left,right);

  else if(left>mid)

  return Qsum(i*2+1,left,right);

  else return Qsum(i*2,left,mid)+Qsum(i*2+1,mid+1,right);   

  }



 int Qmax(int i,int left,int right)

  {

  if(left==tree[i].left && right==tree[i].right)

  return tree[i].max;

  int mid=(tree[i].left+tree[i].right)/2;

  if(right<=mid)

  return Qmax(i*2,left,right);

  else if(left>mid)

  return Qmax(i*2+1,left,right);

  else return   Math.max(Qmax(i*2,left,mid), Qmax(i*2+1,mid+1,right));   

  }



void run() throws IOException {

n = cin.nextInt();

m = cin.nextInt();

Build(1, 1, n);

int value;

for(int i=1;i<=n;i++)

{

value=cin.nextInt();

Insert(1,i,value); 



}



for (int i = 0; i < m; ++i) {

int type = cin.nextInt();

int l = cin.nextInt();

int r = cin.nextInt();

if (type == 1) Update(1, l, r);

else if (type == 2) out.println(Qsum(1, l, r));

else out.println(Qmax(1, l, r));

}

out.close(); 

}



public static void main(String[] args) throws IOException {

new Main2().run();

}



Main2() {

 cin = new InputReader(System.in);

out = new PrintWriter(System.out);

}



PrintWriter out;

 InputReader cin;



class InputReader {

InputReader(InputStream in) {

reader = new BufferedReader(new InputStreamReader(in));



tokenizer = new StringTokenizer("");

}



private String next() throws IOException {

while (!tokenizer.hasMoreTokens()) {

tokenizer = new StringTokenizer(reader.readLine());

}

return tokenizer.nextToken();

}



public Integer nextInt() throws IOException {

return Integer.parseInt(next());

}

private BufferedReader reader;

private StringTokenizer tokenizer;

}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值