[SCOI2007]降雨量 線段樹和區間最值(RMQ)問題
阿新 • • 發佈:2020-07-31
這道題是比較經典的 \(RMQ\) 問題,用線段樹維護是比較簡單好寫的。比較難的部分是判斷處理。如果沒有想好直接打程式碼會調很久(沒錯就是我)。怎麼維護查詢區間最大值我就不再這裡贅述了,不懂線段樹的先去入門(此題也是線段樹入門題)。我講幾個很坑的點(比較坑我的點):
1.詢問的X年降雨量不超過Y,但是中間年份降雨量一定小於X(注意X和Y順序)。
2.X可能等於Y+1年,也就是不用考慮中間年份。
3.區間查詢最值的操作要留意範圍,不同情況下查詢的範圍是不一樣的,這點需要自己理解。
4.錯的最多的 \(maybe\) 和 \(false\) 的判斷,要清楚知道哪個是已知量,哪個是位置量。
本題中我分了四種情況分析,還有眾多 \(if\)
\(Code\)
#include<bits/stdc++.h> using namespace std; #define For(i,sta,en) for(int i = sta;i <= en;i++) #define lowbit(x) x&(-x) #define mid (l+r)/2 #define ls(x) x<<1 #define rs(x) x<<1|1 #define speedUp_cin_cout ios::sync_with_stdio(false);cin.tie(0); cout.tie(0); typedef long long ll; typedef __int128 lll; const int maxn = 2e5+9; int t[maxn],n,m; //t 記錄區間最大值 int year[maxn],rain[maxn]; void update(int now,int l,int r,int pos,int value){ if(l == r) {t[now] = value;return;} if(pos <= mid) update(ls(now),l,mid,pos,value); else update(rs(now),mid+1,r,pos,value); t[now] = max(t[ls(now)],t[rs(now)]); //維護區間最大值 } int query(int now,int l,int r,int x,int y){ //詢問x到y區間最大值 if(x <= l&&r <= y) return t[now]; int an = 0; if(x <= mid) an = query(ls(now),l,mid,x,y); if(y > mid) an = max(an,query(rs(now),mid+1,r,x,y)); return an; } int main(){ speedUp_cin_cout //讀寫優化 #define maybe cout<<"maybe"<<endl;continue;//讓輸出沒這麼難看 #define false cout<<"false"<<endl;continue; #define true cout<<"true"<<endl;continue; cin>>n; int y,r; For(i,1,n) { cin>>y>>r; year[i] = y; rain[i] = r; update(1,1,n,i,r); } cin>>m; int Y,X,p1,p2,f1,f2; //p1 p2是在陣列的位置,f1 f2兩個標記記錄X Y是否已知降水量 For(i,1,m){ cin >> Y >> X; p1 = lower_bound(year+1,year+1+n, Y) - year; //year在輸入時保證是有序的 p2 = lower_bound(year+1,year+1+n, X) - year; f1 = (p1 == n + 1|| year[p1] != Y) ? 0 : 1; f2 = (p2 == n + 1 ||year[p2] != X) ? 0 : 1; //兩年都不知道,可以不管中間如何,都是未知的 if(!f1 && !f2) {maybe} //兩年都知道 if(f1 && f2) { if(rain[p1] < rain[p2]) {false} //X年降水量多於Y年,錯 if(Y + 1 == X ) {true} //X = Y+1年,中間沒有其他年份,而X年降水量一定不大於Y,對 if(p1 + 1 == p2) {maybe} //X不是Y後一年,但是X和Y年間都不知道降雨量,未知 int maxGap = query(1,1,n,p1+1,p2-1); //X和Y間存在已知降水量的年份,在其中找到降雨量最大值 if(maxGap >= rain[p2]) {false} //大於等於都滿足嚴格小於,錯 if(p2 - p1 == X - Y) {true} //滿足嚴格小於後再判斷X和Y間每年降雨量是否都已知 else maybe //不是都已知,即未知 } //後一年不知道,p2 一定大於 p1,只可能是maybe或者false else if(f1){ if( p1 + 1 == p2 ) {maybe} int maxGap = query(1,1,n,p1+1,p2-1); //注意查詢範圍 if(maxGap >= rain[p1]) { false } else maybe } //前一年不知道,p1 有可能等於 p2,只可能是maybe或者false else{ if(p1 == p2 ) {maybe} int maxGap = query(1,1,n,p1,p2-1); //注意查詢範圍 if(maxGap >= rain[p2]) { false } else { maybe } } } return 0; }