本文出自:http://blog.csdn.net/svitter
树状数组用于处理求区间内的值和改变单个元素的值,要注意树状数组从数组下标1开始。
基础算法:
获取全部的lowbit值,防止重复计算。
void getLowbit() { for(int i = 0; i < 1000; i++) lowbit[i] = i & (-i); }
求区间和1~i:
int Sum(int i) { int sum = 0; while(i > 0) { sum += C[i]; i = i - lowbit[i]; } return sum; }
改变一个元素i数值:
void Change(int i, int inc) { while(i <= n) { C[i] += inc; i = i + lowbit[i]; } }
Cn的求法:
sum(n) - sum(n - lowbit(n));
题目:POJ3321
题意:一颗苹果树,树上有多个苹果,一个分支一个苹果,求一个节点以上苹果的个数。操作有添加和删除苹果。(如果原本有苹果,则添加,没有则删除。一开始全部有苹果)。
测试数据:第一行为一个n,代表分支个数。随后输入分支关系。(邻接表)第二行为一个m,代表操作个数。随后输入Q或者C加一个数字,代表求和或者对树进行删除或者添加操作。
思路:考虑是稀疏图使用邻接表存存储。STL_稀疏图,树_使用vector邻接表存储。求段间和,只改变其中一个元素,可以使用树状数组。以根为1,向上节点为另一边。使用深搜统计苹果数量。
C[i]就是Sum(i) - Sum(i - lowbit[i]) 即为 i - (i - lowbit[i]); C[ time ] ;
Q: 使用start[n]和end[n]来存储访问时间,使用( end[n] - start[n] + 1 )/ 2 求出最后结果(除了选择节点的苹果,其他的苹果都走了两遍)。
C: 更改与树状数组的modify结合,更改apple节点。Query函数求出的不是苹果的值。
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> using namespace std; #define MY_MAX 220000 typedef vector<int> VCT_INT; vector <VCT_INT> G(MY_MAX/2); int C[MY_MAX]; int lowbit[MY_MAX]; bool HasApple[MY_MAX]; int start[MY_MAX]; int end[MY_MAX]; int nCount = 0; void DFS(int v) { start[v] = ++ nCount; for(int i = 0; i < G[v].size(); i++) DFS(G[v][i]); end[v] = ++ nCount; } int QuerySum(int p) { int nSum = 0; while(p > 0) { nSum += C[p]; p -= lowbit[p]; } return nSum; } void Modify(int p, int val) { while(p <= nCount) { C[p] += val; p += lowbit[p]; } } void getLowbit() { for(int i = 1; i < MY_MAX; i++) lowbit[i] = i & (-i); } int main() { int n, m; scanf("%d", &n); int x, y, i, j ,k; int a, b; getLowbit(); //build map for(i = 0; i < n - 1; i++) { scanf("%d%d", &a, &b); G[a].push_back(b); } nCount = 0; DFS(1); for(i = 1; i <= n; i++) HasApple[i] = 1; for(i = 1; i <= nCount; i++) C[i] = i - (i - lowbit[i]); scanf("%d", &m); while(m--) { char cmd[10]; scanf("%s%d", cmd, &a); if(cmd[0]== 'C') { if(HasApple[a]) { Modify(start[a], -1); Modify(end[a], -1); HasApple[a] = 0; } else { Modify(start[a], 1); Modify(end[a], 1); HasApple[a] = 1; } } else { int t1 = QuerySum(end[a]); int t2 = QuerySum(start[a]-1); printf("%d\n", (t1-t2)/2); } } return 0; }
时间: 2024-10-30 20:53:03