树状数组和线段树板子

树状数组板子

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
#define IOS ios::sync_with_stdio(false), cin.tie(0) ,cout.tie(0)
using namespace std;
typedef unsigned long long ll;

const int N = 1e3 + 10;
int tree[N];
#define lowbit(x) ((x)&(-x))
void update(int x, int d)
{
	//单点修改:修改元素a[x],使得a[x] += d
	while (x < N)
	{
		tree[x] += d;
		x += lowbit(x);
	}
}
int sum(int x)//查询前缀和,返回前缀和sum=a[1] + a[2] + ... + a[x]
{
	int ans = 0;
	while (x > 0)
	{
		ans += tree[x];
		x -= lowbit(x);
	}
	return ans;
}

核心应用点在于单点修改+ 区间查询,然后改成差分数组可以变成区间修改和单点查询
线段树板子:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
#define IOS ios::sync_with_stdio(false), cin.tie(0) ,cout.tie(0)
using namespace std;
typedef long long ll;
const int N = 1e5+10;
ll a[N];
ll tree[N << 2];//tree[i]是第i个节点的值,表示一个线段区间的‘代表值’,比如区间和、最值
ll tag[N << 2];//tag[i]是第i个节点的lazy-tag,统一记录这个区间的修改
ll ls(ll p) { return p << 1;}
ll rs(ll p) { return p << 1 | 1; }
//push_up可变
void push_up(ll p)
{
	tree[p] = tree[ls(p)] + tree[rs(p)];
	//push_up的功能就是从下到上传递区间值,用于建树
}
void build(ll p, ll pl, ll pr)//建树:p为节点编号,指向区间[pl,pr]
{
	tag[p] = 0;
	if (pl == pr) { tree[p] = a[pl]; return; }//叶子节点
	ll mid = (pl + pr) >> 1;
	build(ls(p), pl, mid);
	build(rs(p), mid + 1, pr);
	push_up(p);
}
//addtag可变
void addtag(ll p, ll pl, ll pr, ll d)
{
	tag[p] += d;
	tree[p] += d * (pr - pl + 1);
}
void push_down(ll p, ll pl, ll pr)
{
	if (tag[p])
	{
		ll mid = (pl + pr) >> 1;
		addtag(ls(p), pl, mid, tag[p]);
		addtag(rs(p), mid + 1, pr, tag[p]);
		tag[p] = 0;
	}
}
//update的根据题目来,可变
void update(ll L, ll R, ll p, ll pl, ll pr, ll d)//区间修改:[L,R]内每个元素+d
{
	if (L <= pl and pr <= R)
	{
		addtag(p, pl, pr, d);
		return;
	}
	push_down(p, pl, pr);
	ll mid = (pl + pr) >> 1;
	if (L <= mid)update(L, R, ls(p), pl, mid, d);//递归左子树
	if (R > mid)update(L, R, rs(p), mid + 1, pr, d);
	push_up(p);
}
ll query(ll L, ll R, ll p, ll pl, ll pr)
{
	//查询区间[L,R],p是当前节点的编号,[pl,pr]是节点p表示的线段区间
	if (pl >= L and pr <= R) { return tree[p]; }
	push_down(p, pl, pr);
	ll res = 0;
	ll mid = (pl + pr) >> 1;
	if (L <= mid)res += query(L, R, ls(p), pl, mid);
	if (R > mid)res += query(L, R, rs(p), mid + 1, pr);
	return res;
}
int main()
{
	ll n, m; cin >> n >> m;//n:数字个数,m:操作次数
	for (ll i = 1; i <= n; i++)cin >> a[i];
	build(1, 1, n);//※
	while (m--)
	{
		ll q, L, R, d; cin >> q;
		if (q == 1)
		{
			cin >> L >> R >> d;
			update(L, R, 1, 1, n, d);

		}
		else 
		{
			cin >> L >> R;
			cout << query(L, R, 1, 1, n);
		}
	}
	return 0;
}

posted on 2024-07-02 21:36  WHUStar  阅读(2)  评论(0编辑  收藏  举报