藍橋杯——操作格子(線段樹)

問題描述

有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;

}

}

 

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