树状数组原理图
查询时
增加时
#include#include using namespace std; const int N = 100010; int w[N]; int tr[N];int n, m; int lowbit(int x) { return x & -x; } int query(int x) { int res = 0; for (int i = x;i;i -= lowbit(i)) res += tr[i]; return res; } void add(int x,int y) { for (int i = x;i <= n;i += lowbit(i)) tr[i] += y; } int main() { ios::sync_with_stdio(false); cin >> n >> m; for (int i = 1;i <= n;i++) { cin >> w[i]; } for(int i=1;i<=n;i++) add(i, w[i]); int x, y,k; while (m--) { cin >> k >> x >> y; if (k == 0) { //求区间a,b和 cout << query(y) - query(x - 1)< ******
线段树做法 建树 *** 作查询 *** 作 修改 *** 作
#include#include using namespace std; const int N = 100005; int w[N]; int n, m; struct node { int l; int r; int sum; //[l,r]的区间和 }tr[4*N]; void bulid(int u, int l, int r) {//先递归进入左右结点,让所有叶子结点都有值之后,再返回来求父结点区间和 if (l ==r) {//u表示结点编号,tr[u]=tr[l]=tr[r] tr[u] = { l,r,w[r] }; return; } tr[u] = { l,r }; //先不赋值 int mid = l + r >> 1; //中点 bulid(u << 1, l , mid ); //去左边建树 bulid(u << 1 | 1, mid + 1, r); //去右边建树 tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum; } int query(int u, int l, int r) { //把一个大问题分割成若干个小问题 //查询操作是把要查询的区间分割成若干个小区间 //然后通过递归,找到这小区间,把他们凑成目标查询区间 if (tr[u].l >= l && tr[u].r <= r) //该区间被查询区间(a,b)完全包含,直接返回 return tr[u].sum; int mid = tr[u].l+tr[u].r >> 1; //l+r/2,分割区间 int sum = 0; if (l <= mid) //左边区间超出 sum += query(u << 1, l, r); //在实参传递的过程中,l,r两个实参作为形参是始终不变的 if (r > mid) //右边区间超出,这里r是大于号,因为建树的时候,右边递归用的是(mid+1,r) sum += query(u << 1 | 1, l, r); return sum; //返回和 } void add(int u, int x, int v) { if (tr[u].l == tr[u].r ) { tr[u].sum += v; return; } int mid = tr[u].l + tr[u].r >> 1; if (x <= mid) add(u << 1, x, v); //x在左边,进入左子树寻找x else add(u << 1 | 1, x, v); //x在右边,进入右子树寻找x tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;//更新值 } int main() { cin >> n >> m; for (int i = 1;i <= n;i++) cin >> w[i]; bulid(1,1,n); //1左结点,n右结点 int a, b,k; while (m--) { cin >> k >> a >> b; if (k == 0) //k==0查询 cout << query(1,a,b)<<'n'; //实参(根结点,左区间,右区间) else //修改 add(1,a,b); //实参(根结点,目标位置,添加值) } } 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)