HDU-3648 Median Filter 树状数组求中位数
参考:http://blog.jobbole.com/96430/
遍历和二分写的比较麻烦。
最后还要注意避免 Presentation Error:行尾有空格。
// Median Filter
// http://acm.hdu.edu.cn/showproblem.php?pid=3648
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
using namespace std;
typedef long long LL;
const int maxn = 510;
const int maxg = 1000010;
int n, r;
int m[maxn][maxn];
int newm[maxn][maxn];
int a[maxg];
int maxcolor = 0;
inline int lowbit(int x) { return x & -x; }
void add(int x, int v) {
for (int i = x; i < maxcolor + 10; i += lowbit(i)) {
a[i] += v;
}
}
int sum(int x) {
int s = 0;
for (int i = x; i ; i -= lowbit(i)) {
s += a[i];
}
return s;
}
void median_filter(int r) {
for (int i = 1; i <= r+r+1; i++) {
for (int j = 1; j <= r+r; j++) {
add(m[i][j], 1);
}
}
for (int i = r + 1; i <= n - r; i++) {
if ( (i - r) & 1 ) {
for (int j = r + 1; j <= n - r; j++) {
for (int k = i - r; k <= i + r; k++) {
add(m[k][j+r], 1);
}
int left = 1, right = maxcolor+1, mid;
int median = (r+r+1) * (r+r+1) / 2;
while (left < right) {
mid = (left + right) >> 1;
if (sum(mid) <= median) {
left = mid + 1;
} else {
right = mid;
}
}
newm[i][j] = left;
for (int k = i - r; k <= i + r; k++) {
add(m[k][j-r], -1);
}
}
if (i < n-r) {
for (int k = n-r-r+1; k <= n; k++) {
add(m[i-r][k], -1);
add(m[i+r+1][k], 1);
}
}
} else {
for (int j = n - r; j >= r + 1; j--) {
for (int k = i - r; k <= i + r; k++) {
add(m[k][j-r], 1);
}
int left = 1, right = maxcolor+1, mid;
int median = (r+r+1) * (r+r+1) / 2;
while (left < right) {
mid = (left + right) >> 1;
if (sum(mid) <= median) {
left = mid + 1;
} else {
right = mid;
}
}
newm[i][j] = left;
for (int k = i - r; k <= i + r; k++) {
add(m[k][j+r], -1);
}
}
if (i < n-r) {
for (int k = r+r; k >= 1; k--) {
add(m[i-r][k], -1);
add(m[i+r+1][k], 1);
}
}
}
}
}
int main() {
while (cin >> n >> r) {
if (!n && !r) break;
maxcolor = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &m[i][j]);
m[i][j]++;
if (maxcolor < m[i][j])
maxcolor = m[i][j];
}
}
memset(a, 0, (maxcolor + 10) * sizeof(int));
median_filter(r);
for (int i = r+1; i <= n-r; i++) {
for (int j = r+1; j <= n-r; j++) {
printf("%d ", newm[i][j]-1);
}
printf("\n");
}
}
return 0;
}