HDU 3954 Level up

HDU_3954

    一开始始终在纠结要怎样维护max,因为不同等级的人每次加的经验是不一样的,这样如果只用一个max来维护最大值的话是很难办的。看了胡浩的出题报告之后恍然大悟,既然一个max来维护是很难办的,那不妨就将max变成K个,max[i]表示等级为i的人的经验的最大值,这样max[i]的增加就很好处理了。

    至于如何处理一个人的升级问题,既然有了max[i],那么我们就知道每个等级上是否有人的经验达到了need[i+1],一旦有人达到就直接找到这个人,并将路径上的max[i]和max[i+1]的值更新一下即可。由于K比较小,每个人最多升级K次,而每次找一个人的复杂度是logN,所以升级操作总的复杂度是K*N*logN,是可以接受的。查询操作就比较好写了。

#include<stdio.h>
#include<string.h>
#define MAXD 10010
#define MAXK 11
#define INF 0x3f3f3f3f
int N, K, QW, max[4 * MAXD][MAXK], add[4 * MAXD], need[MAXK];
void build(int cur, int x, int y)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
    memset(max[cur], -1, sizeof(max[cur]));
    max[cur][1] = add[cur] = 0;
    if(x == y)
        return ;
    build(ls, x, mid);
    build(rs, mid + 1, y);
}
void init()
{
    int i;
    scanf("%d%d%d", &N, &K, &QW);
    for(i = 1; i < K; i ++)
        scanf("%d", &need[i]);
    need[K] = INF;
    build(1, 1, N);
}
int getmax(int x, int y)
{
    return x > y ? x : y;
}
void update(int cur)
{
    int i, ls = cur << 1, rs = (cur << 1) | 1;
    for(i = 1; i <= K; i ++)
        max[cur][i] = getmax(max[ls][i], max[rs][i]);
}
void pushdown(int cur)
{
    int ls = cur << 1, rs = (cur << 1) | 1;
    if(add[cur])
    {
        int i;
        add[ls] += add[cur], add[rs] += add[cur];
        for(i = 1; i <= K; i ++)
        {
            if(max[ls][i] != -1)
                max[ls][i] += i * add[cur];
            if(max[rs][i] != -1)
                max[rs][i] += i * add[cur];
        }
        add[cur] = 0;
    }
}
void change(int cur, int x, int y, int k)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
    if(x == y)
    {
        max[cur][k + 1] = max[cur][k];
        max[cur][k] = -1;
        return ;
    }
    pushdown(cur);
    if(max[ls][k] >= need[k])
        change(ls, x, mid, k);
    else
        change(rs, mid + 1, y, k);
    max[cur][k] = getmax(max[ls][k], max[rs][k]);
    max[cur][k + 1] = getmax(max[ls][k + 1], max[rs][k + 1]);
}
void refresh(int cur, int x, int y, int s, int t, int delta)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
    if(x >= s && y <= t)
    {
        int i;
        add[cur] += delta;
        for(i = 1; i <= K; i ++)
            if(max[cur][i] != -1)
                max[cur][i] += i * delta;
        for(i = 1; i < K; i ++)
            while(max[cur][i] >= need[i])
                change(cur, x, y, i);
        return ;
    }
    pushdown(cur);
    if(mid >= s)
        refresh(ls, x, mid, s, t, delta);
    if(mid + 1 <= t)
        refresh(rs, mid + 1, y, s, t, delta);
    update(cur);
}
void query(int cur, int x, int y, int s, int t, int &ans)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
    if(x >= s && y <= t)
    {
        int i;
        for(i = 1; i <= K; i ++)
            if(max[cur][i] > ans)
                ans = max[cur][i];
        return ;
    }
    pushdown(cur);
    if(mid >= s)
        query(ls, x, mid, s, t, ans);
    if(mid + 1 <= t)
        query(rs, mid + 1, y, s, t, ans);
}
void solve()
{
    int i, j, k, x, y, z, ans;
    char b[5];
    for(i = 0; i < QW; i ++)
    {
        scanf("%s", b);
        if(b[0] == 'W')
        {
            scanf("%d%d%d", &x, &y, &z);
            refresh(1, 1, N, x, y, z);
        }
        else
        {
            scanf("%d%d", &x, &y);
            ans = 0;
            query(1, 1, N, x, y, ans);
            printf("%d\n", ans);
        }
    }
}
int main()
{
    int t, tt;
    scanf("%d", &t);
    for(tt = 0; tt < t; tt ++)
    {
        init();
        printf("Case %d:\n", tt + 1);
        solve();
        printf("\n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/staginner/p/2444294.html