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

来源:互联网 发布:阿里云域名 编辑:程序博客网 时间:2024/06/07 00:54

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


#include <cstdio>#include <cstring>struct SegmentTreeNode{    int l, r, n;} node[1 << (16 + 1) + 1];//2 ^ 16 = 65536 > 50000void 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 50000struct 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
原创粉丝点击