P1531 I Hate It(史上最好懂的線段樹之一)
阿新 • • 發佈:2018-11-07
題目背景
很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。這讓很多學生很反感。
題目描述
不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫一個程式,模擬老師的詢問。當然,老師有時候需要更新某位同學的成績
輸入輸出格式
輸入格式:
第一行,有兩個正整數 N 和 M ( 0<N<=200000,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'的時候,表示這是一條更新操作,如果當前A學生的成績低於B,則把ID為A的學生的成績更改為B,否則不改動。
輸出格式:
對於每一次詢問操作,在一行裡面輸出最高成績
輸入輸出樣例
輸入樣例#1: 複製
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5
輸出樣例#1: 複製
5
6
5
9
這個題超級超級超級裸的線段樹(線段樹是個好東西)
因為不會用樹狀陣列,所以本蒟蒻來一手線段樹(大佬勿噴)
史上最好懂的線段樹之一
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; long long aa[500001],k,n,m; long long init(int n_) { n=1;//為了方便,將葉節點數擴大到2的冪 while(n<=n_){n=n*2;} } long long add(int k,int x) { k=k+n-1; aa[k]=x;//將第k個葉節點修改成x while(k>0) { k=k/2;//向上修改最大值 aa[k]=max(aa[k*2],aa[k*2+1]); } } long long check(int a,int b,int k,int l,int r)//a,b是所求區間範圍,k是當前節點編號,l,r是第k號節點的所管區間 { //注意:根節點為1 if(r<a||l>b) return 0;//如果該節點所管區間與要求區間不重合,返回0 if(a<=l&&r<=b) return aa[k];//如果該節點所管區間完全包含於所求區間,返回該節點的值。 else { long long maxl=check(a,b,k*2,l,(l+r)/2);//左孩子 long long maxr=check(a,b,k*2+1,(l+r)/2+1,r);//右孩子 return max(maxl,maxr);//返回兩個孩子的最大值 } } int main() { cin>>n>>m; int nn=n; init(n);//初始化 for(int i=1;i<=nn;i++) { int x; cin>>x; add(i,x); } for(int i=0;i<m;i++) { char b; cin>>b; int l,r; cin>>l>>r; if(b=='U')//修改 { if(aa[l+n-1]<r) add(l,r); } if(b=='Q')//查詢 cout<<check(l,r,1,1,n)<<endl;//要從根節點開始搜尋 } return 0; }