洛谷 P3368 【模板】树状数组 2(线段树区间加单点查找)

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数数加上x

2.求出某一个数的值

输入格式

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含2或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x 含义:输出第x个数的值

输出格式

输出包含若干行整数,即为所有操作2的结果。

输入输出样例

输入 #1
5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4
输出 #1
6
10

说明/提示

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

故输出结果为6、10

#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
using namespace std;

#define ll long long
#define eps 1e-9

const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;

int n, m, ans, input[500000+8];

struct node
{
    int left, right, num;
}tree[5000000+8];

void build(int left, int right, int index)///建树
{
    tree[index].num = 0;
    tree[index].left = left;
    tree[index].right = right;
    if(left == right)///如果是叶子节点,就返回他的值
        return;
    int mid = (right+left)/2;
    build(left, mid, index*2);///从左边区间开始赋值
    build(mid+1, right, index*2+1);///从右边区间开始赋值
}

void pls(int index, int l, int r, int k)///在[l, r]区间加上k值
{
    if(tree[index].left >= l && tree[index].right <= r)///如果这个区间在目的区间内
    {
        tree[index].num += k;
        return;
    }
    if(tree[index*2].right >= l)///让左边的区间加k
        pls(index*2, l, r, k);
    if(tree[index*2+1].left <= r)///让右边的区间加k
        pls(index*2+1, l, r, k);
}

void search(int index, int dis)///寻找那个点,并记录他的值
{
    ans += tree[index].num;///记录操作后所增加/减少的值
    if(tree[index].left == tree[index].right)
        return;
    if(dis <= tree[index*2].right)///如果这个数小于index这个点的右儿子,那就往左边找
        search(index*2, dis);
    if(dis >= tree[index*2+1].left)///如果这个数大于index这个点的左儿子,那就往右边找
        search(index*2+1, dis);
}

int main()
{
    scanf("%d%d", &n, &m);
    build(1, n, 1);///初始化,给开始的每个值赋为1
    for(int i = 1; i <= n; i++)
        scanf("%d", &input[i]);
    for(int i = 1; i <= m; i++)
    {
        int a;
        scanf("%d", &a);
        if(a == 1)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            pls(1, x, y, z);
        }
        else if(a == 2)
        {
            ans = 0;
            int x;
            scanf("%d", &x);
            search(1, x);///从根节点开始找x这个位置
            printf("%d\n", ans+input[x]);
        }
    }
    return 0;
}

 

posted @ 2019-07-31 19:38  明霞  阅读(272)  评论(0编辑  收藏  举报