• 树状数组-


    目录

    lowbit

    树状数组1

    树状数组2

    逆序对

    树状数组二分

    二维树状数组


    lowbit

    得到x的二进制数的最后一位

    1. int lowbit(int x){
    2. return x & -x
    3. }

    设数组数组为 c[ ]

    c[i] = a_{i-lowbit(i)+1} \rightarrow a_{i}

     

    树状数组1

    • 单点修改
    • 区间查询

    1. // problem :
    2. #include
    3. using namespace std;
    4. #define ll long long
    5. typedef pair<int, int> PII;
    6. #define pb push_back
    7. const int N = 2e5+5;
    8. int a[N], n, q;
    9. ll c[N];
    10. inline int lowbit(int x){
    11. return x & -x;
    12. }
    13. inline void modify(int x, int d){
    14. while(x <= n){
    15. c[x] += d;
    16. x += lowbit(x);
    17. }
    18. }
    19. inline ll query(int x){
    20. ll res = 0;
    21. while(x){
    22. res += c[x];
    23. x -= lowbit(x);
    24. }
    25. return res;
    26. }
    27. int main(){
    28. scanf("%d %d", &n, &q);
    29. for(int i = 1; i <= n; ++i){
    30. scanf("%d", &a[i]);
    31. modify(i, a[i]);
    32. }
    33. while(q--) {
    34. int ty; scanf("%d", &ty);
    35. if(ty == 1) {
    36. int x, d; scanf("%d %d", &x, &d);
    37. modify(x, d - a[x]);
    38. a[x] = d;
    39. }else {
    40. int x; scanf("%d", &x);
    41. printf("%lld\n", query(x));
    42. }
    43. }
    44. return 0;
    45. }

     

    树状数组2

    • 区间修改
    • 区间查询

     这里的mod 2的64次方等价于无符号long long的自然溢出。

    这里配合差分的思想,并且要开两个树状数组来维护。一个维护 d[i]    一个维护  i * d[i]

    1. // problem :
    2. #include
    3. using namespace std;
    4. #define ll long long
    5. typedef pair<int, int> PII;
    6. #define pb push_back
    7. typedef unsigned long long u64;
    8. const int N = 2e5+5;
    9. int n, q;
    10. inline int lowbit(int x){
    11. return x & -x;
    12. }
    13. template<class T>
    14. struct BIT{
    15. T c[N];
    16. int size;
    17. void resize(int n){size = n;}
    18. inline void modify(int x, T d){
    19. while(x <= size){
    20. c[x] += d;
    21. x += lowbit(x);
    22. }
    23. }
    24. inline T query(int x){
    25. T res = 0;
    26. while(x){
    27. res += c[x];
    28. x -= lowbit(x);
    29. }
    30. return res;
    31. }
    32. };
    33. BIT c1, c2;
    34. int main(){
    35. scanf("%d %d", &n, &q);
    36. c1.resize(n);
    37. c2.resize(n);
    38. while(q--) {
    39. int ty; scanf("%d", &ty);
    40. if(ty == 1) {
    41. int l, r;
    42. u64 d;
    43. scanf("%d %d %llu", &l, &r, &d);
    44. c1.modify(l, d);
    45. c1.modify(r + 1, -d);
    46. c2.modify(l, l * d);
    47. c2.modify(r + 1, (r + 1) * (-d));
    48. }else {
    49. int x; scanf("%d", &x);
    50. printf("%llu\n", (x + 1) * c1.query(x) - c2.query(x));
    51. }
    52. }
    53. return 0;
    54. }

     

    逆序对

     用树状数组求解逆序对还是很巧妙的,怎么说的,本身树状数组就是一个很巧妙的东西。

    • 静态转动态的思想
    • hash   (权重)

    problem:记得开ll,要不然结果会溢出。

    1. // problem :
    2. #include
    3. using namespace std;
    4. #define ll long long
    5. typedef pair<int, int> PII;
    6. #define pb push_back
    7. int n;
    8. ll c[100005];
    9. inline int lowbit(int x){
    10. return x & -x;
    11. }
    12. inline void modify(int x, int d){
    13. while(x <= n){
    14. c[x] += d;
    15. x += lowbit(x);
    16. }
    17. }
    18. inline ll query(int x){
    19. int res = 0;
    20. while(x){
    21. res += c[x];
    22. x -= lowbit(x);
    23. }
    24. return res;
    25. }
    26. int main(){
    27. scanf("%d", &n);
    28. ll ans = 0;
    29. for(int i = 1; i <= n; ++i){
    30. int x; scanf("%d", &x);
    31. x = n + 1 - x;
    32. ans += query(x);
    33. modify(x, 1);
    34. }
    35. printf("%lld\n", ans);
    36. return 0;
    37. }

    树状数组二分

     problem:

            树状数组上二分,比较直观的一种理解就是对T进行二分,容易看出时间复杂度为     O(n logn logn) 

            但有一种更加高效的算法,可以使得时间复杂度压缩至O(nlogn)

     树状数组c[i] 存的是一段区间的值,这段区间的起点和长度由i来决定,确切地说,由i的二进制来确定。

    c[i] = a_{i-lowbit(i)+1} \rightarrow a_{i}

    所以我们的S就可以由一段一段的区间分割开来。j从大到小遍历,是表明从大区间到小区间收缩。最终S由若干个区间组成。

    注意,j是可以取到0的,   2的0次方等于1     

    1. // problem :
    2. #include
    3. using namespace std;
    4. #define ll long long
    5. typedef pair<int, int> PII;
    6. #define pb push_back
    7. const int N = 2E5 + 5;
    8. ll c[N], a[N];
    9. int n, q;
    10. inline int lowbit(int x){
    11. return x & -x;
    12. }
    13. inline void modify(int x, ll d){
    14. while(x <= n){
    15. c[x] += d;
    16. x += lowbit(x);
    17. }
    18. }
    19. inline int query(ll s){
    20. int pos = 0;
    21. for(int j = 18; j >= 0; --j)
    22. if(pos + (1 << j) <= n && c[pos + (1 << j)] <= s){
    23. pos += (1 << j);
    24. s -= c[pos];
    25. }
    26. return pos;
    27. }
    28. int main(){
    29. scanf("%d %d", &n, &q);
    30. for(int i = 1; i <= n; ++i){
    31. scanf("%lld", &a[i]);
    32. modify(i, a[i]);
    33. }
    34. while(q--) {
    35. int ty; scanf("%d", &ty);
    36. if(ty == 1){
    37. int x;
    38. ll d;
    39. scanf("%d %lld", &x, &d);
    40. modify(x, d - a[x]);
    41. a[x] = d;
    42. }else {
    43. ll s; scanf("%lld", &s);
    44. printf("%d\n", query(s));
    45. }
    46. }
    47. return 0;
    48. }

    二维树状数组

     

    1. // problem :
    2. #include
    3. using namespace std;
    4. #define ll long long
    5. typedef pair<int, int> PII;
    6. #define pb push_back
    7. int n, m, q;
    8. int a[505][505];
    9. ll c[505][505];
    10. inline int lowbit(int x){
    11. return x & -x;
    12. }
    13. void modify(int x, int y, ll d){
    14. for(int p = x; p <= n; p += lowbit(p))
    15. for(int q = y; q <= m; q += lowbit(q))
    16. c[p][q] += d;
    17. }
    18. ll query(int x, int y){
    19. ll res = 0;
    20. for(int p = x; p; p -= lowbit(p))
    21. for(int q = y; q; q -= lowbit(q))
    22. res += c[p][q];
    23. return res;
    24. }
    25. int main() {
    26. scanf("%d %d %d", &n, &m, &q);
    27. for(int i = 1; i <= n; ++i)
    28. for(int j = 1; j <= m; ++j) {
    29. scanf("%lld", &a[i][j]);
    30. modify(i, j, a[i][j]);
    31. }
    32. while(q--) {
    33. int ty; scanf("%d", &ty);
    34. if(ty == 1) {
    35. int x, y;
    36. ll d;
    37. scanf("%d %d %lld", &x, &y, &d);
    38. modify(x, y, d - a[x][y]);
    39. a[x][y] = d;
    40. } else {
    41. int x, y; scanf("%d %d", &x, &y);
    42. printf("%lld\n", query(x, y));
    43. }
    44. }
    45. return 0;
    46. }

  • 相关阅读:
    2023.9 - MYSQL - 基础命令
    一、设计模式七大设计原则
    [golang]使用mTLS双向加密认证http通信
    【C++】如何使用RapidXML读取和创建XML文件
    微信小程序异步回调函数恶梦和解决办法
    【Transformer从零开始代码实现】(一)输入部件:embedding+positionalEncoding
    Vue实战篇三十五:实现滑动拼图验证登录
    通信协议综述
    服务器之间免密登录
    springboot - 2.7.3版本 - (六)学习如何使用Elasticsearch-8.4.2
  • 原文地址:https://blog.csdn.net/PURSUE__LIFE/article/details/125902241