数据结构

线段树模板(codvs1080)!

2018-06-26  本文已影响7人  不给赞就别想跑哼

时隔多年又再次遨游在C++的海洋之中。
话不多说先上题⬇

*1080 线段树练习

时间限制: 1 s
空间限制: 128000 KB
题目描述
一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数m<10000条。

输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。

输出描述

共m行,每个整数

样例输入
6

4

5

6

2

1

3

4

1 3 5

2 1 4

1 1 9

2 2 6

样例输出

22

22

数据范围及提示 <small style="box-sizing: border-box; font-size: 13px;">Data Size & Hint</small>

1≤N≤100000, m≤10000 。

不出意外的话,大多数人看到这个题目都会想到暴力执法,可仔细看看数据,暴力是O(nm) 的复杂度,100000*10000肯定是超时的,所以我们只好转换思路。

那么就开始今天的主题“线段树”。

顾名思义,它一定是个树的结构,而且是一颗二叉树。
大概是这样的⤵


image.png

每个节点储存的是r,l分别表示该节点存储区间的左右端点,以及ls,rs
分别表示该节点所连接的左右儿子的节点序号,还有s表示此区间的和。
从图中可以看出,节点所存储的区间是逐渐二分下去的。如1号节点是1--8,则他的左右儿子2,3分别储存的是1--4,5--8.依此类推。

执行操作1时从根节点开始判断被修改的点是否在该节点所储存的区间内,如果在,那么就把改节点的s,也就是区间和加上所增加的数值,然后继续判断左右儿子,一直递归下去,便达到了修改数值的目的。

操作2时,也是从根节点开始,如果所给区间包含了节点储存的区间,那么直接返回该节点的s即可,如果二者完全分离直接返回0,如果以上都不满足,则返回左右儿子的返回值之和。有些抽象,需自己动手领悟。。

那么就上代码了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{int l,r,ls,rs,s;}tree[400010];
int a[100010],cnt;
int built(int ll,int rr){
    int u=cnt++;
    tree[u]=(node){ll,rr,-1,-1,0};  
    if(ll<rr){
        int mid=(ll+rr)/2;
        tree[u].ls=built(ll,mid);
        tree[u].rs=built(mid+1,rr);
        tree[u].s=tree[tree[u].ls].s+tree[tree[u].rs].s;
    }
    else tree[u].s=a[ll];
    return u;
}
void add(int v,int o,int p){
    if(tree[v].l<=o&&tree[v].r>=o) tree[v].s+=p;
    else return;
    //if(tree[v].l>p||tree[v].r<p) return;
    //if(tree[v].l==tree[v].r)return;
    add(tree[v].ls,o,p);
    add(tree[v].rs,o,p);
}
int query(int v,int l1,int r1){
    if(tree[v].l>=l1&&tree[v].r<=r1) return tree[v].s;
    if(tree[v].r<l1||tree[v].l>r1) return 0;
    else return query(tree[v].ls,l1,r1)+query(tree[v].rs,l1,r1);
}
int main(){
    int n,m,t,x,y;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int root=built(1,n);
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>t>>x>>y;
        if(t==1) add(root,x,y); 
        else cout<<query(root,x,y)<<endl;
    }
    return 0;
} 

谢谢,请留下您的👍!!

上一篇下一篇

猜你喜欢

热点阅读