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;
}
*/