線段樹入門(建樹,查詢,更新)hdu1754
阿新 • • 發佈:2019-02-12
先來一道純線段樹的題目:
I Hate It
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 75617 Accepted Submission(s): 29141
Problem Description 很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。
這讓很多學生很反感。
不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫一個程式,模擬老師的詢問。當然,老師有時候需要更新某位同學的成績。
Input 本題目包含多組測試,請處理到檔案結束。
在每個測試的第一行,有兩個正整數 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'的時候,表示這是一條更新操作,要求把ID為A的學生的成績更改為B。
Output 對於每一次詢問操作,在一行裡面輸出最高成績。
Sample Input 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
Sample Output 5 6 5 9 Hint
結果可想而知,必定是TLE; 好了那麼線段樹有什麼優點呢? 他的查詢的效率高,從O(n)降到了O(logn)的複雜度,AC程式碼如下:#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; const int min1 = -1e9; int main() { int N, M; int score[maxn]; while (scanf("%d%d",&N,&M)!=EOF){ for (int i=0; i<N; i++){ scanf("%d",&score[i]); } char query; int a, b; for (int k=0; k<M; k++){ getchar();//媽的字元輸入有毒,好不容易才知道原因~~ scanf("%c%d%d",&query, &a, &b); int ans = min1; if (query == 'Q'){ for (int j = a-1; j<=b-1;j++){ if(score[j]>ans){ ans = score[j]; } } printf("%d\n",ans); } else{ score[a-1] = b; } } } return 0; }
這裡說一下大概的思路,首先,不用知道每個點的權值就可以先,建立一棵樹,至於father[]陣列的用處,可以打印出來看到它的作用是記錄單個數組成的區間的編號: 當n = 5時: father[1] = 8, father[2] = 9,依次類推:5, 6, 7; 這麼經典的題目,乖乖滾回去再敲一遍(逃#include <bits/stdc++.h> using namespace std; const int MAX_NODE = 1<<19; const int maxn = 2e6+5; struct Node{ int value; int left, right; }node[MAX_NODE]; int father[maxn]; void buildtree(int i, int l, int r){ node[i].left = l; node[i].right = r; node[i].value = 0; if (l == r){//這一步要放在下面寫,千萬不要放在上面,否則會報錯~~~被坑了好長時間 father[l] = i; return; } buildtree(i*2, l, (int)(floor(l+r)/2.0)); buildtree(i*2+1, (int)(floor(l+r)/2.0)+1, r); } void update_tree(int children){ if (children == 1) return; int father = children/2; int a = node[father*2].value; int b = node[father*2+1].value; node[father].value = max(a, b); update_tree(father); } int MAX_NUMBER; void query(int i, int l, int r){ if (node[i].left == l && node[i].right == r) { MAX_NUMBER = max(node[i].value, MAX_NUMBER); return; } i = i*2;//這裡一開始移位有問題QAQ~~ if (l<=node[i].right){ if (r<=node[i].right) query(i, l, r); else query(i, l, node[i].right); } i++; if (r >= node[i].left){ if (l >= node[i].left) query(i, l, r); else query(i, node[i].left, r); } return ; } int main() { int n, m, g; ios::sync_with_stdio(false); while(cin>>n>>m){ buildtree(1, 1, n); // for (int i=1; i<=9; i++){ // cout<<father[i]<<" "; // } for (int i=1; i<=n; i++){ cin>>g; node[father[i]].value = g; update_tree(father[i]); } string op; int a, b; while (m--){ cin>>op>>a>>b; if (op[0]=='Q'){ MAX_NUMBER = -10000; //cout<<op<<" "<<a<<" "<<b<<endl; query(1, a, b); cout<<MAX_NUMBER<<endl; } else{ node[father[a]].value = b; update_tree(father[a]); } } } return 0; }