分块算法

 

 分块算法相当于一种优雅的暴力,一般块的大小是取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\n", 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());
}

 

posted @ 2019-09-03 18:56  downrainsun  阅读(386)  评论(0编辑  收藏  举报