http://acm.hdu.edu.cn/showproblem.php?pid=3954
题意:初始每个英雄的级别为1,经验为0,M li ri ei表示派li--ri去打怪,每个收获的经验值为当前级别level*ei,Q li ri表示查询li--ri的最大经验。。。
分析:很明显的线段树。。。整段更新,整段查询,但整段更新的时候一段里面每个更新的值不一定一样。。大牛说这是中等难度,都不会啊,水。。。
比赛的时候想着对每个节点用个queue保存lazy情况,结果MLE。。。今天又搞了一天啊。。。
后来借鉴了大牛思想。。。http://blog.csdn.net/wsniyufang/article/details/6702560
主要是要利用最大级数不超过10这个条件。。。对每个节点保存这段里面所有的升级所需的最小的值mn。。。然后更新到这一段时如果ei>=mn,则往下更新,最坏情况下,也只有n*klogn这么多。。。不会超时。。。
还有一种解决方式是对每个结点开一个10的数组,存该节点每一级的最大值。。。。
ps:原来输入优化也可以优化这么多的。。。。
代码:
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
const int MX=0x7fffffff;
const int N=10010;
int n, k, qw, leve[13], ei;
struct node
{
int l, r, mid;
int level, exp, add, mn;
void init()
{
level = 1;
exp = add = 0;
mn = leve[2]/1;
}
} a[N*4];
inline int _max(int a, int b)
{
return a>b?a:b;
}
inline int _min(int a, int b)
{
return a<b?a:b;
}
void build(int l, int r, int p)
{
a[p].l = l;
a[p].r = r;
a[p].mid = (l+r)>>1;
a[p].init();
if(l==r)
return;
build(l, a[p].mid, p*2);
build(a[p].mid+1, r, p*2+1);
}
//将本层lazy值往下传。。。
inline void down(int p)
{
a[p*2].add += a[p].add;
a[p*2].mn -= a[p].add;
a[p*2].exp += a[p].add*a[p*2].level;
a[p*2+1].add += a[p].add;
a[p*2+1].mn -= a[p].add;
a[p*2+1].exp += a[p].add*a[p*2+1].level;
a[p].add = 0;
}
//更新过后用下层的结果更新上层。。
inline void up(int p)
{
a[p].mn = _min(a[p*2].mn, a[p*2+1].mn);
a[p].exp = _max(a[p*2].exp, a[p*2+1].exp);
a[p].level = _max(a[p*2].level, a[p*2+1].level);
}
void update(int l, int r, int p)
{
if(a[p].l==l && r==a[p].r)
{
if(l<r)
{
if(ei>=a[p].mn)
{
down(p);
update(l, a[p].mid, p*2);
update(a[p].mid+1, r, p*2+1);
up(p);
}
else
{
a[p].add += ei;
a[p].exp += ei*a[p].level;
a[p].mn -= ei;
}
return;
}
a[p].exp += ei*a[p].level;
for(int i=a[p].level+1; i<=k && a[p].exp>=leve[i]; i++)
a[p].level = i;
a[p].mn = (leve[a[p].level+1]-a[p].exp)/a[p].level+((leve[a[p].level+1]-a[p].exp)%a[p].level!=0);//mn的值表示什么。。相当关键。。
a[p].add = 0;
return;
}
if(a[p].add!=0)
down(p);
if(r<=a[p].mid)
update(l, r, p*2);
else if(l>a[p].mid)
update(l, r, p*2+1);
else
{
update(l, a[p].mid, p*2);
update(a[p].mid+1, r, p*2+1);
}
up(p);
}
int query(int l, int r, int p)
{
if(a[p].l==l && a[p].r==r)
return a[p].exp;
if(a[p].add!=0)
down(p);
int ans;
if(r<=a[p].mid)
ans = query(l, r, p*2);
else if(l>a[p].mid)
ans = query(l, r, p*2+1);
else
{
ans = _max(query(l, a[p].mid, p*2), query(a[p].mid+1, r, p*2+1));
}
//up(p); //可以不用。因为没有更新,下面不存在会有level变化,上层的值也就不会发生变化。。。
return ans;
}
//450ms
int main()
{
int i, cas1, cas, li, ri;
char op[3];
//freopen("D.in", "w", stdout);
scanf("%d", &cas);
for(cas1=1; cas1<=cas; cas1++)
{
scanf("%d%d%d", &n, &k, &qw);
for(i=2; i<=k; i++)
scanf("%d", &leve[i]);
leve[++k] = MX;
build(1, n, 1);
printf("Case %d:\n", cas1);
while(qw--)
{
scanf("%s%d%d", op, &li, &ri);
if(op[0]=='W')
{
scanf("%d", &ei);
update(li, ri, 1);
}
else
{
printf("%d\n", query(li, ri, 1));
}
}
printf("\n");
}
return 0;
}
/*
//输入优化。。。
//加上这个输入优化之后居然就可以榜首了。。343MS。。时间差不多少了3/4
inline int nextInt() {
char c;
while (c = getchar(), c < '0' || c > '9');
int r = c - '0';
while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0';
return r;
}
int main()
{
int i, j, cas1, cas, li, ri;
char op[3];
//freopen("D.in", "w", stdout);
cas = nextInt();
for(cas1=1; cas1<=cas; cas1++)
{
n=nextInt(); k=nextInt(); qw=nextInt();
for(i=2; i<=k; i++)
leve[i] = nextInt();
leve[++k] = MX;
build(1, n, 1);
printf("Case %d:\n", cas1);
while(qw--)
{
scanf("%s", op);
li = nextInt();
ri = nextInt();
if(op[0]=='W')
{
//scanf("%d", &ei);
ei = nextInt();
update(li, ri, 1);
}
else
{
printf("%d\n", query(li, ri, 1));
}
}
puts("");
}
return 0;
}
*/