生活随笔
收集整理的這篇文章主要介紹了
蓝桥杯-操作格子(java)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
算法訓(xùn)練 操作格子 ?
時(shí)間限制:1.0s ? 內(nèi)存限制:256.0MB
? ?
問(wèn)題描述
有n個(gè)格子,從左到右放成一排,編號(hào)為1-n。
共有m次操作,有3種操作類(lèi)型:
1.修改一個(gè)格子的權(quán)值,
2.求連續(xù)一段格子權(quán)值和,
3.求連續(xù)一段格子的最大值。
對(duì)于每個(gè)2、3操作輸出你所求出的結(jié)果。
輸入格式
第一行2個(gè)整數(shù)n,m。
接下來(lái)一行n個(gè)整數(shù)表示n個(gè)格子的初始權(quán)值。
接下來(lái)m行,每行3個(gè)整數(shù)p,x,y,p表示操作類(lèi)型,p=1時(shí)表示修改格子x的權(quán)值為y,p=2時(shí)表示求區(qū)間[x,y]內(nèi)格子權(quán)值和,p=3時(shí)表示求區(qū)間[x,y]內(nèi)格子最大的權(quán)值。
輸出格式
有若干行,行數(shù)等于p=2或3的操作總數(shù)。
每行1個(gè)整數(shù),對(duì)應(yīng)了每個(gè)p=2或3操作的結(jié)果。
樣例輸入 4 3
1 2 3 4
2 1 3
1 4 3
3 1 4 樣例輸出 6
3 數(shù)據(jù)規(guī)模與約定
對(duì)于20%的數(shù)據(jù)n <= 100,m <= 200。
對(duì)于50%的數(shù)據(jù)n <= 5000,m <= 5000。
對(duì)于100%的數(shù)據(jù)1 <= n <= 100000,m <= 100000,0 <= 格子權(quán)值 <= 10000。
package com.sihai.advance;
import java.util.Scanner;/*** @author sihai**/
public class ALGO_8 {private static int[] arr;//保存所有的格子數(shù)private static int[][] op;//存放操作private static int gridNum;//格子總數(shù)private static int opNum;//操作種數(shù)private static Node[] tree;//線段樹(shù)private static int[] father;//father[i]:表示第i個(gè)格子在線段樹(shù)中的位置private static int tempMax;//用于求區(qū)間最大值private static int tempSum;//用于求區(qū)間權(quán)值和public static void main(String[] args) {init();//初始化,包括輸入?yún)?shù)、構(gòu)建線段樹(shù)fun();}private static void fun(){for(int i=0;i<opNum;i++){int p=op[i][0];int x=op[i][1];int y=op[i][2];switch(p){case 1:arr[x]=y;update(father[x]);break;case 2:tempSum=0;getSum(x,y,1);System.out.println(tempSum);break;case 3:tempMax=Integer.MIN_VALUE;getMax(x,y,1);System.out.println(tempMax);break;}}}// index為區(qū)間的序號(hào)(對(duì)應(yīng)的區(qū)間是最大范圍的那個(gè)區(qū)間,也是第一個(gè)圖最頂端的區(qū)間,一般初始是 1 ) private static void getSum(int x,int y,int index){if(x==tree[index].left&&y==tree[index].right){tempSum+=tree[index].sum;return;}int leftIndex=index*2;//左子樹(shù)在tree中的位置if(x<=tree[leftIndex].right){//所求的區(qū)間在左子樹(shù)中有涉及if(y<=tree[leftIndex].right){//左子樹(shù)完全包含所求的區(qū)間,則查詢區(qū)間形態(tài)不變 getSum(x,y,leftIndex);}else{//半包含于左區(qū)間,則查詢區(qū)間拆分,左端點(diǎn)不變,右端點(diǎn)變?yōu)樽笞訕?shù)的右區(qū)間端點(diǎn) getSum(x,tree[leftIndex].right,leftIndex);}}int rightIndex=leftIndex+1;//右子樹(shù)在tree中的位置if(y>=tree[rightIndex].left){//所求的區(qū)間在右子樹(shù)有涉及if(x>=tree[rightIndex].left){//右子樹(shù)完全包含所求的區(qū)間,則查詢區(qū)間形態(tài)不變 getSum(x,y,rightIndex);}else{// 半包含于右區(qū)間,則查詢區(qū)間拆分,與上同理 getSum(tree[rightIndex].left,y,rightIndex);}}}// index為區(qū)間的序號(hào)(對(duì)應(yīng)的區(qū)間是最大范圍的那個(gè)區(qū)間,也是第一個(gè)圖最頂端的區(qū)間,一般初始是 1) private static void getMax(int x,int y,int index){if(x==tree[index].left&&y==tree[index].right){tempMax=tree[index].max>tempMax?tree[index].max:tempMax;return;}int leftIndex=index*2;//左子樹(shù)在tree中的位置if(x<=tree[leftIndex].right){//所求的區(qū)間在左子樹(shù)中有涉及if(y<=tree[leftIndex].right){//左子樹(shù)完全包含所求的區(qū)間,則查詢區(qū)間形態(tài)不變 getMax(x,y,leftIndex);}else{//半包含于左區(qū)間,則查詢區(qū)間拆分,左端點(diǎn)不變,右端點(diǎn)變?yōu)樽笞訕?shù)的右區(qū)間端點(diǎn) getMax(x,tree[leftIndex].right,leftIndex);}}int rightIndex=leftIndex+1;//右子樹(shù)在tree中的位置if(y>=tree[rightIndex].left){//所求的區(qū)間在右子樹(shù)有涉及if(x>=tree[rightIndex].left){//右子樹(shù)完全包含所求的區(qū)間,則查詢區(qū)間形態(tài)不變 getMax(x,y,rightIndex);}else{// 半包含于左區(qū)間,則查詢區(qū)間拆分,與上同理 getMax(tree[rightIndex].left,y,rightIndex);}}}private static void update(int index){// 從下往上更新(注:這個(gè)點(diǎn)本身已經(jīng)在函數(shù)外更新過(guò)了) if(index==1)return;// 向上已經(jīng)找到了祖先(整個(gè)線段樹(shù)的祖先結(jié)點(diǎn) 對(duì)應(yīng)的下標(biāo)為1) if(tree[index].left==tree[index].right){//該節(jié)點(diǎn)為葉子節(jié)點(diǎn)tree[index].max=arr[tree[index].left];tree[index].sum=arr[tree[index].left];}int fatherIndex=index/2;//代表父節(jié)點(diǎn)在tree中的位置tree[fatherIndex].max=tree[fatherIndex*2].max>tree[fatherIndex*2+1].max?tree[fatherIndex*2].max:tree[fatherIndex*2+1].max;tree[fatherIndex].sum=tree[fatherIndex*2].sum+tree[fatherIndex*2+1].sum;update(fatherIndex);}//初始化,包括輸入?yún)?shù)、構(gòu)建線段樹(shù)private static void init(){Scanner sc=new Scanner(System.in);gridNum=sc.nextInt();opNum=sc.nextInt();arr=new int[gridNum+1];op=new int[opNum][3];tree=new Node[2*gridNum];//線段樹(shù)father=new int[gridNum+1];//father[i]:代表arr[i]在tree中的位置for(int i=1;i<=gridNum;i++){arr[i]=sc.nextInt();//初始化各格子數(shù)}for(int i=0;i<opNum;i++){for(int j=0;j<3;j++){op[i][j]=sc.nextInt();//輸入所有操作}}buildTree(1,gridNum,1);//構(gòu)造線段樹(shù)//更新區(qū)間最大值、區(qū)間和for(int i=1;i<=gridNum;i++){update(father[i]);}sc.close();}//為區(qū)間[left,right]建立一個(gè)以index為祖先的線段樹(shù),index為數(shù)組下標(biāo) private static void buildTree(int left,int right,int index){tree[index]=new Node();tree[index].left=left;tree[index].right=right;if(left==right){// 當(dāng)區(qū)間長(zhǎng)度為 0 時(shí),結(jié)束遞歸 father[left]=index;// 能知道某個(gè)點(diǎn)對(duì)應(yīng)的序號(hào),為了update()的時(shí)候從下往上一直到頂 return;}//該結(jié)點(diǎn)往 左孩子的方向 繼續(xù)建立線段樹(shù),線段的劃分是二分思想,如果寫(xiě)過(guò)二分查找的話這里很容易接受 ,這里將 區(qū)間[left,right] 一分為二了buildTree(left,(int)Math.floor(((left+right)/2.0)),index*2);// 該結(jié)點(diǎn)往 右孩子的方向 繼續(xù)建立線段樹(shù) buildTree((int)Math.floor(((left+right)/2.0))+1,right,index*2+1);}
}class Node{int left;int right;int sum;int max;
}
總結(jié)
以上是生活随笔為你收集整理的蓝桥杯-操作格子(java)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。