Luogu P1531 I Hate It
阿新 • • 發佈:2020-07-26
思路
這道題其實並不難,充其量就是一道線段樹(單點修改+區間維護最大值)的板子。但是基於嚴謹務實的態度,我們還是應該認真看一下這個道題。
線段樹的基本寫法及原理在這裡不再贅述,下面我們來說一下單點修改操作。
這道題的單點修改操作跟線段樹板子的單點修改不太一樣,這道題的單點修改不是單純地將一個點的值改為另一個值,而是對當前點的原本的值與給定的值取一個最大值(其實也沒啥區別,就是在update
的時候把替換操作改為對兩個值取max即可)。單點修改就這些,其實就是把線段樹板子稍稍改動了一下。
區間查詢操作也很簡單,說白了就是把區間求和的操作改成區間求最大值即可。具體操作就是把push_up、build、update和query操作中的求和改為取max即可。具體細節還是看程式碼吧。
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define INF 0x7fffffff #define MAXN 2000010 typedef long long ll; //以上應該沒有疑問 ll n, m, a[MAXN]; ll tree[MAXN<<2]; inline ll read(void){//快讀,其實我也沒用到 ll x = 0, f = 1;char ch; do{ch = getchar();if (ch == '-' )f = -1;}while(ch < '0' || ch > '9'); do{x = x * 10 + ch - '0';ch = getchar();}while (ch >= '0' && ch <= '9'); return f * x; } //求左兒子 inline ll lson(ll k) { return k << 1; } //求右兒子 inline ll rson(ll k) { return k << 1 | 1; } //上傳操作,注意是求max,不是求和 inline void push_up(ll k){ tree[k] = std::max(tree[lson(k)], tree[rson(k)]); return; } //建樹(主程式裡一定不要忘了執行啊!) void build(ll l,ll r,ll k){ if(l==r){//若遍歷到葉子結點,直接賦值 tree[k] = a[l]; return; } //否則分別遍歷左右子樹 ll mid = (l + r) >> 1; //遍歷左子樹 build(l, mid, lson(k)); //遍歷右子樹 build(mid+1,r,rson(k)); //別忘了上傳 push_up(k); return; } void update(ll x,ll l,ll r,ll k,ll v){ if(l==r&&l==x){//若當前節點為需要更改的點 tree[k] = std::max(tree[k], v);//更改取max return; } ll mid = (l + r) >> 1; //若有一部分在左子樹,向左子樹遍歷 if(x<=mid)update(x,l,mid,lson(k),v); //若有一部分在右子樹,向右子樹遍歷 else update(x,mid+1,r,rson(k),v); //上傳 push_up(k); } ll query(int ql,int qr,int l,int r,int k){ ll res = -INF;//賦值成-INF比較保險 if(ql<=l&&r<=qr)return tree[k];//若當前區間被查詢區間完全包括,直接返回 ll mid = (l + r) >> 1; //若查詢區間一部分在左子樹,遍歷左子樹 if(ql<=mid)res=std::max(res,query(ql,qr,l,mid,lson(k))); //若查詢區間一部分在右子樹,遍歷右子樹 if(qr>mid)res=std::max(res,query(ql,qr,mid+1,r,rson(k))); return res; } int main(){ scanf("%lld%lld",&n,&m); for (int i = 1; i <= n;++i) scanf("%lld",&a[i]); //讀入…… build(1,n,1);//千萬別忘了建樹 for (int i = 1; i <= m;++i){ char opt[20]; scanf("%s", opt);//讀入…… if(opt[0]=='Q'){ ll x = 0, y = 0;//查詢x~y區間內的最大值 scanf("%lld%lld", &x, &y); printf("%lld\n", query(x, y, 1, n, 1)); } if(opt[0]=='U'){ ll x = 0, y = 0; scanf("%lld%lld", &x, &y); //將x位置的數與y取max update(x, 1, n, 1, y); } } return 0; }