1. 程式人生 > >最高分是多少

最高分是多少

int swap sub 樹狀 div 某某 編號 describe 大小

最高分是多少

題目描述

老師想知道從某某同學當中,分數最高的是多少,現在請你編程模擬老師的詢問。當然,老師有時候需要更新某位同學的成績.

輸入描述:

輸入包括多組測試數據。
每組輸入第一行是兩個正整數N和M(0 < N <= 30000,0 < M < 5000),分別代表學生的數目和操作的數目。
學生ID編號從1編到N。
第二行包含N個整數,代表這N個學生的初始成績,其中第i個數代表ID為i的學生的成績
接下來又M行,每一行有一個字符C(只取‘Q’或‘U’),和兩個正整數A,B,當C為‘Q‘的時候, 表示這是一條詢問操作,他詢問ID從A到B(包括A,B)的學生當中,成績最高的是多少
當C為‘U’的時候,表示這是一條更新操作,要求把ID為A的學生的成績更改為B。

輸出描述:

對於每一次詢問操作,在一行裏面輸出最高成績.
示例1

輸入

5 7
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 4 5
U 2 9
Q 1 5

輸出

5
6
5
9

分析:

這個題目樹狀數組線段樹都是OK的,但是沒有涉及到對區間的操作,樹狀數組在時間和空間上面的代價都要小很多。

牛客網題解:

暴力,線段樹,塊狀鏈表

鏈接:https://www.nowcoder.com/questionTerminal/3897c2bcc87943ed98d8e0b9e18c4666
來源:牛客網

華為仿佛找了一種比較奇特的方法來區分應聘者啊。
先來說說這題的3種做法: 最簡單的就是暴力了。每次查詢直接做。 修改復雜度O(1),查詢復雜度O(N)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <stdio.h> #include <algorithm> using namespace std; const int MAXN=100000; int data[MAXN+5]; int querymax ( int l , int r ) { int ans=data[l]; for(int i=l+1;i<=r;i++) ans=max(ans,data[i]); return ans; } void update(int idx,int value){ data[idx]=value; } int
main(){ int n,m; while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++){ scanf("%d",&data[i]); } char order; int a,b; for(;m--;){ scanf(" %c%d%d",&order,&a,&b); if(order==‘U‘){ update(a,b); }else if(order==‘Q‘){ if(a>b)swap(a,b); printf("%d\n",querymax(a,b)); } } } return 0; }
……如果他們手一抖,寫成N<=100000,M<=100000怎麽辦? !!!註意:以下內容涉及高級數據結構!!! 首先,有ACM經驗的選手,一看這個題,第一反應,線段樹好~ 線段樹這種數據結構,修改O(logn),查詢O(logn),但是要預處理O(nlogn) 這個,如果沒有ACM經驗,也不打算認真做ACM的同學,看看就好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <stdio.h> #include <algorithm> using namespace std; const int MAXN=100000; int data[MAXN+5]; int maxarr[MAXN*4+5]; void build(int p,int l,int r) { if(l==r){ maxarr[p]=data[l]; return ; } int m = ( l + r ) >> 1 ; int lchild=p<<1,rchild=p<<1|1; build ( lchild , l , m ) ; build ( rchild , m+1 , r ) ; maxarr[p]=max(maxarr[lchild],maxarr[rchild]); } int querymax ( int L , int R , int p , int l , int r ) { if ( L <= l && r <= R ) { return maxarr[p]; } int m = ( l + r ) >> 1 ; int lans=-1,rans=-1; if ( L <= m ) lans=querymax ( L , R , p << 1 , l , m ) ; if ( m < R ) rans=querymax ( L , R , p << 1 | 1 , m + 1 , r ) ; if(lans==-1)return rans; if(rans==-1)return lans; return max(lans,rans); } void update(int idx,int value,int p,int l,int r){ if(l==r&&l==idx){ maxarr[p]=value; return; } int m = ( l + r ) >> 1 ; if ( idx <= m ) update( idx, value, p << 1, l, m ); if ( m < idx ) update( idx, value, p << 1|1, m+1, r ); maxarr[p]=max(maxarr[p<<1],maxarr[p<<1|1]); } int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++){ scanf("%d",&data[i]); } build(1,1,n); char order; int a,b; for(;m--;){ scanf(" %c%d%d",&order,&a,&b); if(order==‘U‘){ update(a,b,1,1,n); }else if(order==‘Q‘){ if(a>b)swap(a,b); printf("%d\n",querymax(a,b,1,1,n)); } } } return 0; }
有沒有什麽辦法,普通人能去想出來,又不需要專門去學過高級數據結構呢? 有一個,叫塊狀鏈表(其實塊狀數組也行吧)。 好吧,其實分塊的思想也不怎麽常見,談針對面試的算法的思路,都談分治、貪心、遞推、動態規劃,沒見人說過分塊的樣子。但是,分塊是比較容易理解的。 很簡單,現在我們把整個N大小的數組按順序拆成sqrt(n)(根號n)個小數組,每個小數組有sqrt(n)個元素 比如 1 2 3 4 5 6 7 8 9 現在拆成 1 2 3 4 5 6 7 8 9 然後對每一個小塊,我們除了改掉相應位置的值,還要額外記錄一下整個小塊的最大值。 如果我更新的時候,那個小塊的最大值增大,那很簡單,最大值也增大了。 如果把最大值改小了呢?為了正確性,只能把整個小塊掃一遍,重新算出最大值了。 所以,修改的復雜度是O(sqrt(n)) 現在看查詢。我們要充分利用分小塊以後的信息。 比如要查詢2到9的最大值。按之前最樸素的暴力的做法,我要訪問2、3、4、5、6、7、8、9 現在有小塊的最大值信息了,我只要判斷每個小塊是否在查詢區間內,不在的沒用,一部分在的,就暴力查找,如果是完整在查詢區間內的,我們就利用之前算好的這個小塊內的最大值。 所以,分塊的情況下,查詢2到9的最大值,需要看看2、3,以及4~6的最大值,7~9的最大值。 很容易證明,查詢的復雜度是O(sqrt(n))的(最壞是sqrt(n)個塊全部要用,左右2邊只蓋住sqrt(n)-1個數,要暴力遍歷過去) //TODO:在這裏補上分塊法的代碼
3種流派全部可過,但是明顯的,在極限數據情況下,能夠輕易區分出普通應聘者,會動腦的應聘者和有ACM經驗的應聘者了。

最高分是多少