【HDU1166 敌兵布阵】 线段树、树状数组入门(1)

版权声明: https://blog.csdn.net/leelitian3/article/details/81880022

数据结构介绍

线段树(Segment Tree)

树状数组,即二叉索引树(Binary Index Tree)

典型例题

HDU1166敌兵布阵

这题只涉及到单点修改,关于区间修改:【洛谷模板题】 线段树、树状数组入门(2)

线段树解法

#include <iostream>
using namespace std;
#define LEFT(x) (x << 1)
#define RIGHT(x) ((x << 1) | 1)
int seg[50005 * 4];         //4倍防越界

void pushUp(int a)      //由2个子树更新root
{
    seg[a] = seg[LEFT(a)] + seg[RIGHT(a)];
}

void build(int root, int low, int high)
{
    if(low == high)
    {
        cin >> seg[root];   //输入
        return;
    }
    int mid = (low + high) / 2;
    build(LEFT(root), low, mid);            //递归建树
    build(RIGHT(root), mid + 1, high);
    pushUp(root);
}

void update(int root, int low, int high, int pos, int add)  //若区间包含了单点,则更新
{
    seg[root] += add;
    if(low == high) return;
    int mid = (low + high) / 2;
    if(pos <= mid)
        update(LEFT(root), low, mid, pos, add);
    else
        update(RIGHT(root), mid + 1, high, pos, add);
}

int getSum(int root, int low, int high, int l, int h)
{
    if(l <= low && high <= h)       //当前区间[low,high]被包含在查询区间[l,r]内部
        return seg[root];
    int res = 0;
    int mid = (low + high) / 2;
    if(l <= mid)                    //区间左边与[l,h]有交集
        res += getSum(LEFT(root), low, mid, l, h);
    if(h > mid)
        res += getSum(RIGHT(root), mid + 1, high, l, h);
    return res;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t, n, a, b;
    string op;
    cin >> t;
    for(int i = 1; i <= t; ++i)
    {
        cout << "Case " << i << ":\n";
        cin >> n;
        build(1, 1, n);
        while(cin >> op && op != "End")
        {
            cin >> a >> b;
            if(op == "Query")
                cout << getSum(1, 1, n, a, b) << '\n';
            else if(op == "Add")
                update(1, 1, n, a, b);
            else update(1, 1, n, a, -b);
        }
    }
    return 0;
}

树状数组解法

#include <iostream>
#include <cstring>
using namespace std;
#define lowbit(x) ((x)&(-x))

int t, n, tmp, a, b;
string op;
int c[50005];               //c[i]保存了Σ([i-lowbit(i)+1,i])

void update(int x, int add) //x+lowbit(x)即为其父节点
{
    while(x <= n)
    {
        c[x] += add;
        x += lowbit(x);
    }
}

int getSum(int x)       //如求1~6,此时x=6
{
    int res = 0;        //(110) = (10) + (100)
    while(x)
    {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> t;
    for(int i = 1; i <= t; ++i)
    {
        cout << "Case " << i << ":\n";
        cin >> n;
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; ++i)
        {
            cin >> tmp;
            update(i, tmp);
        }
        while(cin >> op && op != "End")
        {
            cin >> a >> b;
            if(op == "Query")
                cout << getSum(b) - getSum(a - 1) << '\n';
            else if(op == "Add")
                update(a, b);
            else update(a, -b);
        }
    }
    return 0;

}

猜你喜欢

转载自blog.csdn.net/leelitian3/article/details/81880022