转载标记处: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; }