----------------------------------------------------------
线性分块, 国外通常把块大小为 sqrt(n) 的分块方式叫做 “SQRT Decomposition”。
资料:
《入门经典:训练指南》P395
http://sysmagazine.com/posts/138946/
http://algoacm.com/Algorithms/sqrt_decomposition/sqrt_decomposition.html
题目:
Uva 12003 Array Transformer
#include<bits/stdc++.h>
using namespace std;
#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
typedef long long LL;
struct Edge{
int u, v, c;
Edge(){}
Edge(int u, int v, int c):u(u), v(v), c(c){}
int getAdj(int x) {
return x == u ? v : u;
}
};
const int Maxn = 300000;
const int SIZE = 4096;
int n, m, u, a[Maxn+5], block[Maxn/SIZE+5][SIZE], numBlock, numLastBlock;
//#define DEBUG
void init() {
cin >> n >> m >> u;
int b = 0, j = 0;
rep(i, 0, n-1) {
cin >> a[i];
block[b][j] = a[i];
++j;
if (j == SIZE) {++b;j=0;}
}
rep(i, 0, b-1) sort(block[i], block[i]+SIZE);
if (j) sort(block[b], block[b]+j);
numBlock = b;
numLastBlock = j ? j : SIZE;
}
int countOrderedRange(const int * l, const int * r, int v) {
int ret = 0;
for (const int *p=l;p<=r;++p) {
if (*p < v) ++ret;
}
return ret;
}
int Query(int L, int R, int v) {
int lb = L/SIZE, rb = R/SIZE, ret = 0;
rep(i, lb+1, rb-1) {
ret += lower_bound(block[i], block[i]+SIZE, v) - block[i];
}
if (lb == rb) {
ret += countOrderedRange(a+L, a+R, v);
}
else {
ret += countOrderedRange(a+L, a+(lb+1)*SIZE-1, v);
ret += countOrderedRange(a+rb*SIZE, a+R, v);
}
return ret;
}
void Update(int p, int x) {
int * B = block[p/SIZE];
int old = a[p];
a[p] = x;
const int bSize = p/SIZE == numBlock ? numLastBlock : SIZE;
int pos = lower_bound(B, B+bSize, old) - B;
#ifdef DEBUG
cout << "in update: old->" << old << " pos->" << pos << endl;
cout << "Elements in this block: ";
rep(i, 0, bSize-2) cout << B[i] << ' ';cout << B[bSize-1] << endl;
#endif
while (pos > 0 && x < B[pos-1]) {
B[pos] = B[pos-1];
--pos;
}
while (pos < bSize-1 && x > B[pos+1]) {
B[pos] = B[pos+1];
++pos;
}
B[pos] = x;
}
void printBlocks() {
cout << "-------Show Blocks-------" << endl;
rep(i, 0, numBlock-1) {
cout << "Block " << i << ": ";
rep(j, 0, SIZE-2) cout << block[i][j] << ' ';cout << block[i][SIZE-1] << endl;
}
cout << "Block " << numBlock << ": ";
rep(j, 0, numLastBlock-2) cout << block[numBlock][j] << ' ';cout << block[numBlock][numLastBlock-1] << endl;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
SPEED_UP
init();
//printBlocks();
while (m--) {
int L, R, v, p;
cin >> L >> R >> v >> p;
--L;--R;--p;
int k = Query(L, R, v);
Update(p, u*1ll*k/(R-L+1));
#ifdef DEBUG
cout << "Q: " << L << ' ' << R << ' ' << v << ' ' << p << " k: " << k << endl;
printBlocks();
#endif
}
rep(i, 0, n-1) cout << a[i] << endl;
return 0;
}
hdu 5057 Argestes and Sequence
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
typedef long long LL;
#define Maxn 100000
#define SIZE 256
const int numBlocks = Maxn/SIZE+1;
int pow10[11];
int a[Maxn+5], b[numBlocks+5][11][10], szLastBlock, n, m;
void clear(int n) {
rep(i, 0, n/SIZE+1) rep(j, 0, 10) rep(k, 0, 9) b[i][j][k] = 0;
}
void init() {
scanf("%d%d", &n, &m);
clear(n);
rep(i, 0, n-1) {
scanf("%d", a+i);
int t = a[i];
rep(j, 1, 10) {
b[i/SIZE][j][t%10] += 1;
t /= 10;
}
}
szLastBlock = n%SIZE;
if (!szLastBlock)
szLastBlock = SIZE;
}
void Update(int p, int x) {
int old = a[p], idx = p/SIZE;
a[p] = x;
rep(i, 1, 10) {
b[idx][i][old%10] -= 1;
b[idx][i][x%10] += 1;
old /= 10;
x /= 10;
}
}
int countRange(int L, int R, int D, int P) {
int ret = 0;
rep(i, L, R) {
int t = a[i]/pow10[D-1]%10;
if (t == P) ++ret;
}
return ret;
}
int Query(int idx, int D, int P) {
int r = idx/SIZE, ret = 0;
rep(i, 0, r-1) ret += b[i][D][P];
ret += countRange(r*SIZE, idx, D, P);
return ret;
}
void printBlocks() {
cout << "-------Show Blocks-------" << endl;
rep(i, 0, numBlocks-1) {
cout << "Block " << i << ": " << endl;;
rep(d, 1, 10)
rep(j, 0, 9){
cout << "digit " << d << "=" << j << ": " << b[i][d][j] << endl;
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
//SPEED_UP
pow10[0] = 1;
rep(i, 1, 10) pow10[i] = pow10[i-1]*10;
int T;
scanf("%d", &T);
char ch;
int aa, bb, cc, dd;
while (T--) {
init();
rep(i, 1, m) {
getchar();
scanf("%c", &ch);
if (ch == 'Q') {
scanf("%d%d%d%d", &aa, &bb, &cc, &dd);
printf("%d\n", Query(bb-1, cc, dd)-Query(aa-2, cc, dd));
}
else {
scanf("%d%d", &aa, &bb);
Update(aa-1, bb);
}
}
}
return 0;
}
codeforces 13E - Holes
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <map>
using namespace std;
#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
typedef long long LL;
#define Maxn 100000
#define SIZE 256
const int numBlocks = Maxn/SIZE+1;
// 每个分块保存其左右端点
struct node{
int l, r;
};
node b[numBlocks+5];
int power[Maxn+5], nxt[Maxn+5], cnt[Maxn+5], n, m;
void update(int i) {
int idx = i + power[i], iBlock = i/SIZE;
if (idx >= n) {
nxt[i] = idx;
cnt[i] = 1;
}
else if (idx/SIZE == iBlock) {
nxt[i] = nxt[idx];
cnt[i] = cnt[idx]+1;
}
else {
nxt[i] = idx;
cnt[i] = 1;
}
}
void init() {
scanf("%d%d", &n,&m);
rep(i, 0, n-1) scanf("%d", power+i);
rep(i, 0, n/SIZE) {
b[i].l = i*SIZE;
b[i].r = (i+1)*SIZE-1;
}
b[n/SIZE].r = n-1;
urep(i, n-1, 0) update(i);
}
int jump_in_block(int x) {
int iBlock = x/SIZE, idx = x;
while (idx + power[idx] < n) idx = idx + power[idx];
return idx;
}
void Update(int p, int x) {
power[p] = x;
int iBlock = p/SIZE;
// 每当更新一个位置,要将同一分块中且在其前的位置全部更新
urep(i, p, b[iBlock].l) update(i);
}
void Jump(int x) {
int idx = x, c = 0, old, last;
//cout << "---- test " << x << " ----\n";
while (idx < n) {
old = idx;
c += cnt[idx];
if (nxt[idx] >= n) {
last = jump_in_block(idx);
}
idx = nxt[idx];
//if (idx < n)
// cout << "from " << old << " jump to " << idx << " with " << cnt[old] << " jumps\n";
}
//cout << "last visit: " << last << " jumps: " << c << endl;
//cout << last+1 << ' ' << c << endl;
printf("%d %d\n", last+1, c);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
//SPEED_UP
init();
int op, aa, bb;
rep(i, 1, m) {
//cin >> op;
scanf("%d", &op);
if (!op) {
//cin >> aa >> bb;
scanf("%d%d", &aa, &bb);
Update(aa-1, bb);
}
else {
//cin >> aa;
scanf("%d", &aa);
Jump(aa-1);
}
}
return 0;
}