简单的线段树(无PUSH_DOWN)
建树
建树需要使得每次区间长减半,要创造出4*n的结点
void build(int p, int l, int r)
{
tr[p] = {l, r, 0};
if (l == r)
{
tr[p].num = a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
}
单点查询
查询的时候只用根据x 而找到对应的结点即可
void Q(int p, int x)
{
ans += tr[p].num;
if (tr[p].l == tr[p].r)
return;
int mid = tr[p].l + tr[p].r >> 1;
if (x <= mid)
Q(p << 1, x);
else
Q(p << 1 | 1, x);
}
区间增减
区间增减只用放到线段树的上层,不过这也是简单线段树的弊端,无法做到区间查询,只能单点查询
void modify(int p, int l, int r, int k)
{
if (tr[p].l >= l && tr[p].r <= r)
{
tr[p].num += k;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
if (l <= mid)
modify(p << 1, l, r, k);
if (r > mid)
modify(p << 1 | 1, l, r, k);
}
P3374 【模板】树状数组 1的AC代码
#include <iostream>
using namespace std;
int n, m;
int ans;
const int N = 5e5 + 10;
int a[N];
struct SegTree
{
struct Node
{
int l, r;
int num;
} tr[4 * N];
void build(int p, int l, int r)
{
tr[p] = {l, r, 0};
if (l == r)
{
tr[p].num = a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
}
void modify(int p, int l, int r, int k)
{
if (tr[p].l >= l && tr[p].r <= r)
{
tr[p].num += k;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
if (l <= mid)
modify(p << 1, l, r, k);
if (r > mid)
modify(p << 1 | 1, l, r, k);
}
void Q(int p, int x)
{
ans += tr[p].num;
if (tr[p].l == tr[p].r)
return;
int mid = tr[p].l + tr[p].r >> 1;
if (x <= mid)
Q(p << 1, x);
else
Q(p << 1 | 1, x);
}
} ST;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
ST.build(1, 1, n);
while (m--)
{
int c;
cin >> c;
if (c == 1)
{
int a, b, c;
cin >> a >> b >> c;
ST.modify(1, a, b, c);
}
else
{
int x;
cin >> x;
ans = 0;
ST.Q(1, x);
cout << ans << endl;
}
}
}