HDU1166敌兵布阵【线段树入门训练】

 一。形象理解:

本题是“ 单点更新 ”的模板题。

线段树几个必要函数,1.建树BuildTree, 2.更新Update , 3. 查询Query

1. 建树:

BuildTree(int l, int r, int k) //建立一颗从l 到 r的二叉树,k表示当前建立的点。

{
    T[k].l = l;
    T[k].r = r;
    if(l == r) {
        scanf("%d",&T[k].v");        //“递归出口:”,到了叶子节点,左右相等,故输入数值即可。
        return;
    }
                                    //“递归过程:”
    int mid = (l + r) / 2;
    BuildTree(l, mid, k*2);        //递归建立左节点,序号为2 * k;
    BuildTree(mid+1, r, k*2+1);    //递归建立右节点。

    T[k].v = T[2*k].v + T[2*k+1].v;    //递归后更新这个节点的值。
}
2. 更新:

void Update(int c, int v, int k) {    //给第c个物体增加v的价值,当前的位置为k 。(1 <= c <= N)
    if(T[c].l == T[c].r && T[c].l == c) {
        T[k].v += v;                    //“递归出口:”,如果找到了相应值,增加该节点值并返回。
        return;
    }
    int mid = (T[c].l + T[c].r)/2;      //“递归过程:”,二分直到找到c点。
    if(c < mid) Update(c, v, 2*k);
    else Update(c, v, 2*k+1);
    
    T[k].v = T[2*k].v + T[2*k+1].v;    //记得要更新值啊
}

    
3. 查询:

int ans;                                //ans保存的是查询的和,记得每次要归 0

void Query(int l, int r, int k) {        //查询操作,从l点到r点的sum,从k点查询。
    if( l > T[k].r || r < T[k].l) {        //出界,out
        return;
    }
    if( l <= T[k].l && r >= T[k].r) {    //如果查询的内容在这个区间内,添加ans
        ans += T[k].v;                   //“递归出口:”
        return;    
    }
                                        //“递归过程:”如果在左边显然是查询左边,如果在右边
    int mid = (T[k].l + T[k].r) / 2;    //显然是查询右边,如果横跨左右,则查询在左边查询左
    if(r <= mid)                        //边的部分,在右边查询右边的方法。
        Query(l, r, 2*k);
    else if(l > mid)
        Query(l, r, 2*k+1);
    else {
        Query(1, mid, 2*k);
        Query(mid+1, r, 2*k+1);
    }
}

二。实例代码:

#include <iostream>
#include <cstdio>
using namespace std;

int t, n, p = 0;
const int N = 100010;
struct segTree{
    int l, r;
    int v;
}T[N*4];

void Build(int l, int r, int k) {
    T[k].l = l, T[k].r = r;
    if(l == r) {
        scanf("%d", &T[k].v);
        return;
    }
    int mid = (l + r) / 2;
    Build(l, mid, k*2);
    Build(mid+1, r, k*2+1);
    T[k].v = T[k*2].v + T[k*2+1].v;
}
int ans;

void Update(int c, int v, int k) {
    if(T[k].l == T[k].r && T[k].l == c) {
        T[k].v += v;
        return;
    }
    int mid = (T[k].l + T[k].r)/2;
    if(c <= mid) Update(c, v, k*2);
    else Update(c, v, k*2+1);
    T[k].v = T[k*2].v + T[k*2+1].v;
}

void Query(int l, int r, int k) {
    //printf("Query(%d, %d, %d)\n",l, r, k);    //注释掉这句话可以看到递归的详细过程
    if(l > T[k].r || r < T[k].l) {
        return;
    }
    if(l <= T[k].l && r >= T[k].r) {
        ans += T[k].v;
        return;
    }
    int mid = (T[k].l + T[k].r) / 2;
    if(r <= mid) Query(l, r, k*2);
    else if( l > mid) Query(l, r, k*2+1);
    else {
        Query(l, mid, k*2);
        Query(mid+1, r, k*2+1);
    }
}

int main() {
    scanf("%d",&t);
    while(t--) {
        scanf("%d", &n);
        Build(1, n, 1);
        char op[10];
        printf("Case %d:\n", ++p);
        while(scanf("%s", op), op[0]!='E') {
            int u, v;
            scanf("%d%d", &u, &v);
            if(op[0] == 'A') {
                Update(u, v, 1);
            }else if (op[0] == 'S') {
                Update(u, -v, 1);
            }else {
                ans = 0;
                Query(u, v, 1);
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

三。相似例题:

HDU1754  I hate it 

四。如何训练:

搜索网传的Kuangbin带你飞【线段树系列】https://cn.vjudge.net/article/187,练习其中的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值