搜索
查看: 1923|回复: 9
打印 上一主题 下一主题

[分享] 线段树求和

[复制链接]
跳转到指定楼层
楼主
发表于 2017-10-9 21:02:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
[mw_shl_code=c,true]#include <cstdio>
struct Tree
{
    int l, r;
    long long sum;
} tr[1024000];
int a[1024000];
void Build_Tree ( int x , int y , int i )
{
    tr.l = x;
    tr.r = y;
    if( x == y )tr.sum = a[x] ; //找到叶子节点,赋值
    else
    {
        int mid = (tr.l + tr.r ) / 2 ;
        Build_Tree ( x , mid , i * 2); //左子树
        Build_Tree ( mid + 1 , y , i * 2 + 1); //右子树
        tr.sum = tr[i * 2].sum + tr[i * 2 + 1].sum; //回溯维护区间和
    }
}

long long Query_Tree ( int q , int w , int i )
{
    if ( q <= tr.l && w >= tr.r ) return tr.sum; //当前结点的区间完全被目标区间包含
    else
    {
        long long mid = (tr.l + tr.r) / 2;
        if( q > mid ) //完全在左儿子
        {
            return Query_Tree ( q , w , i * 2 + 1);
        }
        else if (w <= mid ) //完全在右儿子
        {
            return Query_Tree ( q , w , i * 2);
        }
        else //目标区间在左右都有分布
        {
            return Query_Tree ( q , w , i * 2) + Query_Tree ( q , w , i * 2 + 1 );
        }
    }
}
int main ( )
{
    int N, M, q, val, l, r;
    scanf("%d", &N);
    for ( int i = 1 ; i <= N ; i++ )scanf("%d", &a);
    Build_Tree ( 1 , N , 1);
    scanf("%d%d", &l, &r);
            printf("%lld\n", Query_Tree ( l , r, 1 ));

    return 0 ;
}[/mw_shl_code]
推荐
 楼主| 发表于 2017-10-16 18:38:22 | 只看该作者
4399APPLE 发表于 2017-10-14 11:18
表示 zkw 线段树大法好啦
常数小到上天
1s 下普通线段树递归 n=10^6 就挂了

没错 一直忘记 问你 你是哪个省份的 现在是高中生还是大学生了?
推荐
发表于 2017-10-14 11:18:34 | 只看该作者
表示 zkw 线段树大法好啦
常数小到上天
1s 下普通线段树递归 n=10^6 就挂了
沙发
 楼主| 发表于 2017-10-9 21:10:10 | 只看该作者
struct Tree
{
    int l, r;
    long long sum;
} tr[1024000];
void Build_Tree ( int x , int y , int i )
{
    tr.l = x;
    tr.r = y;
    if( x == y )tr.sum = a[x] ; //找到叶子节点,赋值
    else
    {
        ll mid = (tr.l tr.r ) / 2 ;
        Build_Tree ( x , mid , i * 2); //左子树
        Build_Tree ( mid + 1 , y , i * 2 + 1); //右子树
        tr.sum = tr[i * 2].sum + tr[i * 2 + 1].sum; //回溯维护区间和
    }
}

void Update_Tree ( int q , int val , int i )
{
    if(tr.l == q && tr.r == q) //找到需要修改的叶子节点
    {
        tr.sum = val ; //更新当前结点
    }
    else //当前结点是非叶子结点
    {
        long long mid = (tr.l tr.r ) / 2 ; //取中间
        if ( q <= mid ) //目标节点在左儿子中
        {
            Update_Tree ( q , val , i * 2 );
        }
        else if( q > mid ) //目标节点在右儿子中
        {
            Update_Tree ( q , val , i * 2 + 1 );
        }
        tr.sum = tr[i * 2].sum + tr[i * 2 + 1].sum; //回溯
    }
}

long long Query_Tree ( int q , int w , int i )
{
    if ( q <= tr.l && w >= tr.r ) return tr.sum; //当前结点的区间完全被目标区间包含
    else
    {
        long long mid = (tr.l tr.r) / 2;
        if( q > mid ) //完全在左儿子
        {
            return Query_Tree ( q , w , i * 2 + 1);
        }
        else if (w <= mid ) //完全在右儿子
        {
            return Query_Tree ( q , w , i * 2);
        }
        else //目标区间在左右都有分布
        {
            return Query_Tree ( q , w , i * 2) + Query_Tree ( q , w , i * 2 + 1 );
        }
    }
}

int main ( )
{

    int N, M, q, val, l, r;
    scanf("%d", &N);
    for ( int i = 1 ; i <= N ; i++ )scanf("%d", &a);
    Build_Tree ( 1 , N , 1);
    cin >> M ;
    while (M--)
    {
        int op ;
        cin >> op ;
        if ( op == 1 )
        {
            scanf("%d%d", &q, &val);
            Update_Tree ( q , val , 1);
        }
        else
        {
            scanf("%d%d", &l, &r);
            printf("%lld\n", Query_Tree ( l , r, 1 ));
        }
    }
    return 0 ;
}

http://www.cnblogs.com/JVxie/p/4854719.html
http://www.cnblogs.com/shadowland/p/5870339.html

地板
 楼主| 发表于 2017-10-16 18:36:02 | 只看该作者
[mw_shl_code=c,true]#include <cstdio>
struct Tree
{
    int l, r;
    long long sum;
} tr[1024000];
int a[1024000];
void Build_Tree ( int x , int y , int i )
{
    tr.l = x;
    tr.r = y;
    if( x == y ) tr.sum = a[x] ; //找到叶子节点,赋值
    else
    {
        int mid = (tr.l + tr.r ) / 2 ;
        Build_Tree ( x , mid , i * 2); //左子树
        Build_Tree ( mid + 1 , y , i * 2 + 1); //右子树
        tr.sum = tr[i * 2].sum + tr[i * 2 + 1].sum; //回溯维护区间和
    }
}

long long Query_Tree ( int q , int w , int i )
{
    if ( q <= tr.l && w >= tr.r ) return tr.sum; //当前结点的区间完全被目标区间包含
    else
    {
        long long mid = (tr.l + tr.r) / 2;
        if( q > mid ) //完全在左儿子
        {
            return Query_Tree ( q , w , i * 2 + 1);
        }
        else if (w <= mid ) //完全在右儿子
        {
            return Query_Tree ( q , w , i * 2);
        }
        else //目标区间在左右都有分布
        {
            return Query_Tree ( q , w , i * 2) + Query_Tree ( q , w , i * 2 + 1 );
        }
    }
}

void Update_Tree ( int q , int val , int i )
{
    if(tr.l == q && tr.r == q) //找到需要修改的叶子节点
    {
        tr.sum += val ; //更新当前结点
    }
    else //当前结点是非叶子结点
    {
        long long mid = (tr.l + tr.r ) / 2 ; //取中间

        if ( q <= mid ) //目标节点在左儿子中
        {
            Update_Tree ( q , val , i * 2 );
        }
        else if( q > mid ) //目标节点在右儿子中
        {
            Update_Tree ( q , val , i * 2 + 1 );
        }
        tr.sum = tr[i*2].sum + tr[i*2+1].sum; //回溯
    }
}
int main ( )
{
    int N, M, q, val, l, r;
    scanf("%d", &N);
    for ( int i = 1 ; i <= N ; i++ )
                scanf("%d", &a);
    Build_Tree ( 1 , N , 1);
    scanf("%d",&M);
    while (M--)
    {
        int op ;
        scanf("%d",&op);
        if ( op == 1 )
        {
            scanf("%d%d", &q, &val);
            Update_Tree ( q , val , 1);
        }
        else
        {
            scanf("%d%d", &l, &r);
            printf("%lld\n", Query_Tree ( l , r, 1 ));
        }
    }
    return 0 ;
}

[/mw_shl_code]

点评

天花乱坠!@_@  发表于 2017-12-10 08:03
5#
 楼主| 发表于 2017-10-16 18:36:18 | 只看该作者
给你n个数,有两种操作:
1:给第i个数的值增加X
2:询问区间[a,b]的总和是什么?
输入描述
输入文件第一行为一个整数n,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数q,再接
下来有q行,表示q个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给
位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。

样例输入
4
7 6 3 5
2
1 1 4
2 1 2

样例输出
17


数据范围


1 <= n,q <= 100000
7#
发表于 2017-10-17 12:00:19 | 只看该作者
啊哈磊 发表于 2017-10-16 18:38
没错 一直忘记 问你 你是哪个省份的 现在是高中生还是大学生了?

GD 初三蒟蒻                                       

点评

希望我到初三时也能像你一样,(本人五年级,能做对大多数NOIP普及组的题)  发表于 2018-2-11 11:15
8#
发表于 2017-10-17 12:05:15 | 只看该作者
啊哈磊 发表于 2017-10-16 18:38
没错 一直忘记 问你 你是哪个省份的 现在是高中生还是大学生了?

补充一下
未进队
以前那个 for noi 是某学长搞的
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

广播台
特别关注
快速回复 返回顶部 返回列表