敌兵布阵问题

本文介绍了一种利用线段树解决区间查询与点更新问题的方法。通过实例详细展示了线段树构建、更新及查询的过程,并提供了完整的代码实现。

一 问题描述

A 国在海岸线沿直线部署了 N 个工兵营地,C 国通过先进的监测手段,对 A 国的每个工兵营里的人数都掌握的一清二楚,每个工兵营的人数都可能发生变动,可能增加或减少若干人数。

二 输入和输出

1 输入

第 1 行包含一个整数,T 表示有 T 组数据。每组数据的第 1 行都包含一个正整数,N 表示 N 个工兵营地。接下来的 N 个正数数,第 i 个正数数 ai 代表第 i 个工兵营地开始时有 ai 个人,在接下来的每行都有 1 条命令,每组数据最多有40000 条命令。命令有四种形式。

Add i j:第 i 个营地增加 j 个人

Sub i j:第 i 个营地减少 j 个人

Query i j:查询第 i ~ j 个营地的总人数

End:退出

2 输出

对第 i 组数据,首先单行输出 Case i,然后对每个 Query 都单行输出查询区间的总人数。

三 输入和输出样例

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

2 输出样例

Case 1:
6
33
59

四 分析和设计

1 分析

本问题包含点更新和区间查询,可以采用树状数组或者线段树解决。

2 算法设计

a 创建线段树存储区间和。

b 点更新,查询到该点后进行点更新,返回时更新区间和。

c 区间查询,首先查找该区间,然后返回区间和值。

五 代码

package com.platform.modules.alg.alglib.hdu1166;

public class Hdu1166 {
    public String output = "";
    private final int maxn = 55555;
    private int a[] = new int[maxn];
    private int sum[] = new int[maxn << 2];

    // 更新和值
    void PushUP(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }

    // 构建线段树
    void build(int l, int r, int rt) {
        if (l == r) {
            sum[rt] = a[l];
            return;
        }
        int m = (l + r) >> 1;
        build(l, m, rt << 1);
        build(m + 1, r, rt << 1 | 1);
        PushUP(rt);
    }

    // 单点更新
    void update(int p, int add, int l, int r, int rt) {
        if (l == r) {
            sum[rt] += add;
            return;
        }
        int m = (l + r) >> 1;
        if (p <= m) update(p, add, l, m, rt << 1);
        else update(p, add, m + 1, r, rt << 1 | 1);
        PushUP(rt);
    }

    // 区间查询
    int query(int L, int R, int l, int r, int rt) {
        if (L == l && r == R)//判断条件为相等
            return sum[rt];
        int m = (l + r) >> 1;
        if (R <= m)
            return query(L, R, l, m, rt << 1);
        else if (L > m)
            return query(L, R, m + 1, r, rt << 1 | 1);
        else return query(L, m, l, m, rt << 1) + query(m + 1, R, m + 1, r, rt << 1 | 1);
    }

    public String cal(String input) {
        int n;
        String[] line = input.split("\n");
        n = Integer.parseInt(line[0]); // 10
        String[] nums = line[1].split(" ");
        for (int x = 1; x <= n; x++)
            a[x] = Integer.parseInt(nums[x - 1]);
        build(1, n, 1);
        int count = 2;
        while (true) {
            String[] command = line[count++].split(" ");
            if (command[0].equals("End")) break;
            int i = Integer.parseInt(command[1]);
            int j = Integer.parseInt(command[2]);
            if (command[0].equals("Query")) {
                output += query(i, j, 1, n, 1) + "\n";
            } else if (command[0].equals("Sub")) {
                update(i, -j, 1, n, 1);
            } else {
                update(i, j, 1, n, 1);
            }
        }
        return output;
    }
}

六 测试

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值