hdu 3954(线段树区间更新)
生活随笔
收集整理的這篇文章主要介紹了
hdu 3954(线段树区间更新)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載標記處:http://www.cnblogs.com/wang-jue/articles/2920341.html
思路:這道題所得到的經驗與每個英雄的等級有關,一般的可能就用線段樹一直更新到每一個英雄,但這樣肯定會超時的。所以我就在想如何使用lazy思想,我發現如果這一段區間內的英雄都已經是最高等級了,那么這一段內肯定是可以用lazy標記的,寫完之后TLE了。于是搜到這篇博客,他最開始的思路也是和我一樣。這里其實有一個隱含的信息,如果這一段區間內的英雄都沒有能夠升級的,那么毫無疑問這一段區間內是可以用lazy標記的,如果這一段區間內有英雄要升級的話,那么就更新到葉子節點。這樣我們就需要多增加一個域,表示這段區間內如果有英雄要升級,他所需要的最少經驗。仔細想想,如果這一段區間沒有英雄要升級,那么這段區間內的最大經驗值肯定是直接加上最大的等級*倍率即可。所以lazy只需要記錄每次輸入的倍率即可。這是這道題最難想到的地方。
先來份我的TLE的代碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std;const int maxn = 10005; struct Segment {int l,r;int max_exp,rank;int lazy,cover; }tree[maxn<<2]; int n,k,m,exprience[15];void build(int rt,int l,int r) {tree[rt].l = l, tree[rt].r = r;tree[rt].rank = 1;tree[rt].max_exp = tree[rt].lazy =tree[rt].cover = 0;if(l == r) return;int mid = (l + r) >> 1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); }void PushDown(int rt) {if(tree[rt].lazy){tree[rt<<1].lazy += tree[rt].lazy;tree[rt<<1|1].lazy += tree[rt].lazy;tree[rt<<1].max_exp += k * tree[rt].lazy;tree[rt<<1|1].max_exp += k * tree[rt].lazy;tree[rt].lazy = 0;} }void update(int rt,int l,int r,int val) {if(tree[rt].l == tree[rt].r){tree[rt].max_exp += tree[rt].rank * val;if(tree[rt].max_exp >= exprience[tree[rt].rank+1] && tree[rt].rank < k)tree[rt].rank++;if(tree[rt].rank >= k) {tree[rt].cover = 1;tree[rt].rank = k;}return;}if(tree[rt].cover && l <= tree[rt].l && tree[rt].r <= r){tree[rt<<1].cover = tree[rt<<1|1].cover = 1;tree[rt].lazy += val;tree[rt].max_exp += k * val;return;}PushDown(rt);int mid = (tree[rt].l + tree[rt].r) >> 1;if(l <= mid) update(rt<<1,l,r,val);if(mid < r) update(rt<<1|1,l,r,val);if(tree[rt<<1].cover && tree[rt<<1|1].cover)tree[rt].cover = 1;tree[rt].max_exp = max(tree[rt<<1].max_exp,tree[rt<<1|1].max_exp); }int query(int rt,int l,int r) {if(l <= tree[rt].l && tree[rt].r <= r)return tree[rt].max_exp;PushDown(rt);int mid = (tree[rt].l + tree[rt].r) >> 1;int ans = 0;if(l <= mid) ans = max(ans,query(rt<<1,l,r));if(mid < r) ans = max(ans,query(rt<<1|1,l,r));return ans; }int main() {int t,cas = 1,a,b,c;char str[2];scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&k,&m);for(int i = 2; i <= k; i++)scanf("%d",&exprience[i]);build(1,1,n);printf("Case %d:\n",cas++);while(m--){getchar();scanf("%s",str);if(str[0] == 'W'){scanf("%d%d%d",&a,&b,&c);update(1,a,b,c);}else{scanf("%d%d",&a,&b);printf("%d\n",query(1,a,b));}}}return 0; }
這個是看懂了別人的思路打的代碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std;const int maxn = 10005; struct Segment {int l,r;int max_exp,dis_min,rank;int lazy; }tree[maxn<<2]; int n,k,m,exprience[15];void build(int rt,int l,int r) {tree[rt].l = l, tree[rt].r = r;tree[rt].rank = 1;tree[rt].dis_min = exprience[2];tree[rt].max_exp = tree[rt].lazy = 0;if(l == r) return;int mid = (l + r) >> 1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); }void PushUp(int rt) {tree[rt].max_exp = max(tree[rt<<1].max_exp,tree[rt<<1|1].max_exp);tree[rt].dis_min = min(tree[rt<<1].dis_min,tree[rt<<1|1].dis_min);tree[rt].rank = max(tree[rt<<1].rank,tree[rt<<1|1].rank); }void PushDown(int rt) {if(tree[rt].lazy){tree[rt<<1].lazy += tree[rt].lazy;tree[rt<<1|1].lazy += tree[rt].lazy;tree[rt<<1].max_exp += tree[rt<<1].rank * tree[rt].lazy;tree[rt<<1|1].max_exp += tree[rt<<1|1].rank * tree[rt].lazy;tree[rt<<1].dis_min -= tree[rt].lazy;tree[rt<<1|1].dis_min -= tree[rt].lazy;tree[rt].lazy = 0;} }void update(int rt,int l,int r,int val) {if(l <= tree[rt].l && tree[rt].r <= r){if(tree[rt].dis_min > val) //區間內無英雄升級{tree[rt].lazy += val;tree[rt].max_exp += tree[rt].rank * val;tree[rt].dis_min -= val;return;}else if(tree[rt].l == tree[rt].r){tree[rt].max_exp += tree[rt].rank * val;while(tree[rt].max_exp >= exprience[tree[rt].rank + 1])tree[rt].rank++;tree[rt].dis_min = (exprience[tree[rt].rank + 1] - tree[rt].max_exp) / tree[rt].rank + ((exprience[tree[rt].rank + 1] - tree[rt].max_exp) % tree[rt].rank != 0);return;}}PushDown(rt);int mid = (tree[rt].l + tree[rt].r) >> 1;if(l <= mid) update(rt<<1,l,r,val);if(mid < r) update(rt<<1|1,l,r,val);PushUp(rt); }int query(int rt,int l,int r) {if(l <= tree[rt].l && tree[rt].r <= r)return tree[rt].max_exp;PushDown(rt);int mid = (tree[rt].l + tree[rt].r) >> 1;int ans = 0;if(l <= mid) ans = max(ans,query(rt<<1,l,r));if(mid < r) ans = max(ans,query(rt<<1|1,l,r));return ans; }int main() {int t,cas = 1,a,b,c;char str[2];scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&k,&m);for(int i = 2; i <= k; i++)scanf("%d",&exprience[i]);exprience[k+1] = 1 << 30;build(1,1,n);printf("Case %d:\n",cas++);while(m--){getchar();scanf("%s",str);if(str[0] == 'W'){scanf("%d%d%d",&a,&b,&c);update(1,a,b,c);}else{scanf("%d%d",&a,&b);printf("%d\n",query(1,a,b));}}printf("\n");}return 0; }
總結
以上是生活随笔為你收集整理的hdu 3954(线段树区间更新)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: activeMQ,spring的jmst
- 下一篇: HTML5 Canvas实现360度全景