hdu 1166

题目概述

有N个营地,编号1到N,起初都有人,根据调查,每个营地的人会增加(Add),减少(Sub),上司会不定时询问(Query)连续几个营地总人数,求每次上司询问时回答的结果

时限

1000ms/2000ms

输入

第一行正整数times,其后times组数据,每组数据第一行正整数N,下一行N个正整数,代表初始人数,其后若干行,每行一个字符串以及两个正整数a,b,对Add和Sub,a为变动的营地序号,b为变动数量,对于Query,a,b分别代表询问区间的左右边界,每组输入到字符串为End结束

限制

1<=N<=50000;1<=初始人数<=50;1<=命令总数<=40000

输出

每组输出第一行为字符串
Case #:
其中#为数据序数,从1开始,其后若干行,每行一个数,为询问的回答

样例输入

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End

样例输出

Case 1:
6
33
59

讨论

线段树,这题不知道做过多少遍了,都是用来回忆线段树的内容,非常基础,没有什么算法,只是练习线段树,速度倒是比以前快了一些

题解状态

280MS,4848K,1626 B,C++

题解代码

#include
#include
#include
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 50003
#define memset0(a) memset(a,0,sizeof(a))

struct it//item 线段树的节点结构
{
    int l, r;//left right 节点代表的左右边界
    int v;//value 节点值
    int mk = 0;//mark 修改标记 默认是0
}its[MAXN * 4];//线段树总是4倍大小 不知道为什么
int N;//营地总数
char cmd[10];//存放输入命令的字符串
void build(int i, int l, int r)//构造树 i是index 内部参数 递归时用到的节点下标 l,r是left,right 边界范围
{
    its[i].l = l, its[i].r = r, its[i].v = its[i].mk = 0;//初始化范围 顺手清零
    if (l != r) {//只要不是一个点
        build(i * 2, l, (l + r) / 2);
        build(i * 2 + 1, (l + r) / 2 + 1, r);//继续递归构造左右子树
    }
}
int query(int i, int l, int r)//查询 i是内部参数 l,r是查询范围
{
    if (its[i].mk) {//有修改标记的先处理标记
        its[i].v += its[i].mk;
        its[i].mk = 0;
    }
    if (l <= its[i].l&&r >= its[i].r)//查询范围覆盖节点范围
        return its[i].v;//直接返回节点值
    if (l > its[i].r || r < its[i].l)//查询范围在节点范围外面
        return 0;//啥也没有
    int suml = query(i * 2, l, r);
    int sumr = query(i * 2 + 1, l, r);//对多余部分递归查询
    return suml + sumr;//求和返回
}
void modify(int i, int pos, int dv)//修改 实际上就是做个标记 i是内部参数 pos是position 单点修改的下标 dv是变动值
{
    its[i].mk += dv;//先给当前节点做上修改标记
    if (its[i].l == its[i].r&&its[i].l == pos)//如果是叶子节点
        return;//直接返回
    int mid = (its[i].l + its[i].r) / 2;//取得子节点的分界
    if (pos <= mid)//以修改位置决定递归方向
        modify(i * 2, pos, dv);
    else
        modify(i * 2 + 1, pos, dv);
}
void fun()
{
    build(1, 1, N);//先行初始化
    for (int p = 1; p <= N; p++) {
        int num;
        scanf("%d", &num);//input
        modify(1, p, num);//利用修改操作赋初值
    }
    while (scanf("%s", cmd) && cmd[0] != 'E') {//input
        int a, b;
        scanf("%d%d", &a, &b);//input
        if (cmd[0] == 'A')
            modify(1, a, b);
        else if (cmd[0] == 'S')
            modify(1, a, -b);
        else
            printf("%d\n", query(1, a, b));//output
    }
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int times;
    scanf("%d", ×);//input
    for (int p = 1; p <= times; p++) {
        printf("Case %d:\n", p);//output//第一行固定输出
        scanf("%d", &N);//input
        fun();
    }
}

EOF

你可能感兴趣的:(树状数组/线段树,hdu)