• 分块算法


     分块算法相当于一种优雅的暴力,一般块的大小是取sqrt(n);

     第一题:区间加法与区间查值。

    修改区间时,两头的区间要格外来加,中间的直接加区间标记值即可。两头的小区间枚举也只有sqrt(n)的复杂度,中间的大区间枚举也只有sqrt(n)的复杂度。

    查询区间时,直接等于那点的值加上所在区间的标记值。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
     
    using LL = long long;
    LL getint();
    int N, M;
    LL block, val[500005], blg[500005], tag[1005];
    void add(int l, int r, int key);
     
    int main(){
      N = getint(), block = sqrt(N);
      int i;
      for(i = 1; i <= N; i++)
        val[i] = getint();
      for(i = 1; i <= N; i++)
        blg[i] = (i - 1) / block + 1;
      for(i = 1; i <= N; i++){
        int op, x, y, key;
        op = getint(), x = getint();
        y = getint(), key = getint();
        if(op == 0){
          add(x, y, key);
        }else
          printf("%lld
    ", val[y] + tag[blg[y]]);
      }
      return 0;
    }
     
    void add(int l, int r, int key){
      int i, top;
      for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++)
        val[i] += key;
      if(blg[l] != blg[r])
        for(i = (blg[r] - 1) * block + 1; i <= r; i++)
          val[i] += key;
      for(i = blg[l] + 1; i <= blg[r] - 1; i++)
        tag[i] += key;
    }
     
    LL getint(){
      LL res = 0, mark = 1;
      char ch = getchar();
      while(ch<'0' || ch>'9'){
        if(ch == '-') mark = -1;
        ch = getchar();
      }
      while(ch >= '0' && ch <= '9')
        res = 10 * res + ch - '0', ch = getchar();
      return mark * res;
    }

    分块第二题

    区间加法与询问某个区间内大于某个数的个数。

    先对每个块排好序,然后对于每个块二分查找即可。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <vector>
    using namespace std;
     
    using LL = long long;
    int N;
    LL block, val[50005], blg[50005], tag[1005];
    vector<LL> val_blg[1005];
    void add(int, int, int);
    int query(int, int, int);
     
    int main(){
      ios::sync_with_stdio(false);
      cin >> N, block = sqrt(N);
      int i;
      for(i = 1; i <= N; i++)
        cin >> val[i];
      for(i = 1; i <= N; i++)
        blg[i] = (i - 1) / block + 1, val_blg[blg[i]].push_back(val[i]);
      for(i = 1; i <= blg[N]; i++)
        sort(val_blg[i].begin(), val_blg[i].end());
      for(i = 1; i <= N; i++){
        int op, x, y, key;
        cin >> op >> x >> y >> key;
        if(op == 0) add(x, y, key);
        else cout << query(x, y, key * key) << endl;
      }
      return 0;
    }
     
    void reset(int block_id);
    void add(int l, int r, int key){
      int i, top;
      for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++)
        val[i] += key;
      reset(blg[l]);
      if(blg[l] != blg[r]){
        for(i = (blg[r] - 1) * block + 1; i <= r; i++)
          val[i] += key;
        reset(blg[r]);
      }
      for(i = blg[l] + 1; i <= blg[r] - 1; i++)
        tag[i] += key;
    }
     
    int query(int l, int r, int key){
      int i, top, res = 0;
      for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++)
        if(val[i] + tag[blg[i]] < key) res++;
      if(blg[l] != blg[r])
        for(i = (blg[r] - 1) * block + 1; i <= r; i++)
          if(val[i] + tag[blg[i]] < key) res++;
      for(i = blg[l] + 1; i <= blg[r] - 1; i++)
        res += lower_bound(val_blg[i].begin(), val_blg[i].end(), key - tag[i]) - val_blg[i].begin();
      return res;
    }
     
    void reset(int x){
      int i, top;
      val_blg[x].clear();
      for(i = (x - 1) * block + 1, top = min(x * block, 1LL * N); i <= top; i++)
        val_blg[x].push_back(val[i]);
      sort(val_blg[x].begin(), val_blg[x].end());
    }
  • 相关阅读:
    setStyleSheet来设定窗口部件的样式
    Qt中设置widget背景颜色/图片的注意事项(使用样式表 setStyleSheet())
    Qt编程—去掉标题栏和设置窗口透明用法
    php设计模式总结
    典型的MVC架构图
    搜索引擎设计分析
    社区论坛设计分析
    (二) vim的Tabbar插件
    目录结构设计分析
    用户注册系统分析
  • 原文地址:https://www.cnblogs.com/downrainsun/p/11454870.html
Copyright © 2020-2023  润新知