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