HDOJ-1166(线段树点更新 + 区间查询)

试了一个完全二叉树,貌似效率有点低:


#include <cstdio>
#include <cstring>

struct SegmentTreeNode{
    int l, r, n;
} node[1 << (16 + 1) + 1];//2 ^ 16 = 65536 > 50000

void build(int l, int r, int index)
{
    node[index].l = l;
    node[index].r = r;
    node[index].n = 0;
    if(l == r) return;
    build(l, (r + l) >> 1, index << 1);
    build(((r + l) >> 1) + 1, r, (index << 1) + 1);
}
void addLeaf(int index, int n)
{
    for(; index; index >>= 1) node[index].n += n;
}
int query(int l, int r, int index)
{
    if(node[index].l == l && node[index].r == r) return node[index].n;
    
    int m = (node[index].l + node[index].r) >> 1;
    if(m >= r) return query(l, r, index << 1);
    else if(m < l) return query(l, r,(index << 1) + 1);
    else return query(l, m, index << 1) + query(m + 1, r, (index << 1) + 1);
}

int minInPower2(int num)
{
    int n = 1;
    for(; n < num; n <<= 1) ;
    return n;
}

int main()
{
    int t, test, n, m, i, v;
    char cmd[8];
    
    for(scanf("%d", &test), t = 1; t <= test; ++t){
        printf("Case %d:\n", t);
    //input point count and get the minimum number in power 2 larger than count
        scanf("%d", &n);
        m = minInPower2(n);
    //build full binary segment tree
        build(1, m, 1);
    //init all leaves
        for(i = 0; i < n; ++i){
            scanf("%d", &v);
            addLeaf(m + i, v);
        }
    //input operations
        while(true){
            scanf(" %s", cmd);
            if(strcmp(cmd, "End") == 0) break;
            scanf("%d %d", &i, &v);
            if(strcmp(cmd, "Add") == 0) addLeaf(m + i - 1, v);
            else if(strcmp(cmd, "Sub") == 0) addLeaf(m + i - 1, -v);
            else printf("%d\n", query(i, v, 1));
        }
    }
    
    return 0;
}

再试了一下非完全二叉树:


#include <cstdio>
#include <cstring>
#define MAX_RANGE 50000

struct SegmentTreeNode{
    int l, r, n;
} node[MAX_RANGE * 3];

void build(int l, int r, int index)
{
    node[index].l = l;
    node[index].r = r;
    node[index].n = 0;
    if(l == r) return;
    build(l, (r + l) >> 1, index << 1);
    build(((r + l) >> 1) + 1, r, (index << 1) + 1);
}
void addLeaf(int leaf, int num, int index)
{
    node[index].n += num;
    if(node[index].l == node[index].r) return;
    
    int m = (node[index].l + node[index].r) >> 1;
    if(m >= leaf) addLeaf(leaf, num, index << 1);
    else addLeaf(leaf, num, (index << 1) + 1);
}
int query(int l, int r, int index)
{
    if(node[index].l == l && node[index].r == r) return node[index].n;
    
    int m = (node[index].l + node[index].r) >> 1;
    if(m >= r) return query(l, r, index << 1);
    else if(m < l) return query(l, r,(index << 1) + 1);
    else return query(l, m, index << 1) + query(m + 1, r, (index << 1) + 1);
}

int main()
{
    int t, test, n, i, v;
    char cmd[8];
    
    for(scanf("%d", &test), t = 1; t <= test; ++t){
        printf("Case %d:\n", t);
    //input range and build tree
        scanf("%d", &n);
        build(1, n, 1);
    //init all leaves
        for(i = 1; i <= n; ++i){
            scanf("%d", &v);
            addLeaf(i, v, 1);
        }
    //input operations
        while(true){
            scanf(" %s", cmd);
            if(strcmp(cmd, "End") == 0) break;
            scanf("%d %d", &i, &v);
            if(strcmp(cmd, "Add") == 0) addLeaf(i, v, 1);
            else if(strcmp(cmd, "Sub") == 0) addLeaf(i, -v, 1);
            else printf("%d\n", query(i, v, 1));
        }
    }
    
    return 0;
}

貌似更慢了,目测是因为完全二叉树从下至上递推的更新区间比非完全二叉树从上至下递归的更新区间效率高些。


刚学了下树状数组,貌似树状数组的操作好简单的样子,而这一题简直就是为了树状数组而生的嘛:


#include <cstdio>
#include <cstring>

int n, C[50001] = {0};
inline int lowbit(int x){
    return x & -x; 
}
void add(int x, int d){
    while(x <= n){
        C[x] += d;
        x += lowbit(x);
    }
}
int sum(int x)
{
    int res = 0;
    while(x){
        res += C[x];
        x -= lowbit(x);
    }
    return res;
}

int main()
{
    int t, test, i, x, d;
    char cmd[8];
    
    for(scanf("%d", &test), t = 1; t <= test; ++t){
        printf("Case %d:\n", t);
        scanf("%d", &n);
    //initialize
        memset(C + 1, 0, n << 2);
        for(i = 1; i <= n; ++i){
            scanf("%d", &d);
            add(i, d);
        }
    //operations
        while(scanf(" %s", cmd), strcmp(cmd, "End")){
            scanf("%d %d", &x, &d);
            if(!strcmp(cmd, "Add")) add(x, d);
            else if(!strcmp(cmd, "Sub")) add(x, -d);
            else printf("%d\n", sum(d) - sum(x-1));
        }
    }
    
    return 0;
}
可以看到无论在时间、空间、还是代码量上,树状数组都完胜啊,果真是个好东西……


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值