http://acm.hdu.edu.cn/showproblem.php?pid=3648
题意:给出一个n*n的矩阵,现在对于(r+1, r+1) to (n-r, n-r)中每个点,以其为中心的规模为(2r+1)*(2r+1)的子矩阵,替换其中间元素为该子矩阵的中位数。
n<=500 元素<=10^6。
采用S型处理(r+1, r+1) to (n-r, n-r)这个区间,这样每次只需要删一行添一行即可。采用树状数组插入删除和查找中位数。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//const double eps=1e-7;
//const double INF=1e50;
//const double pi=acos(-1);
#define N 505
#define M 1000005
int c[N][N],c1[N][N],a[M],lowbit[M],Max;
//树状数组从前往后求和,用来解第k大(或小)的数
int f_kth(int k)//log(n)复杂度
{
int ans = 0, cnt = 0, i;
for (i = 20; i >= 0; i--)//利用二进制的思想,把答案用一个二进制数来表示
{
ans += (1 << i);
if (ans >= Max|| cnt + a[ans] >= k)//这里大于等于k的原因是可能大小为ans的数不在a[ans]的控制范围之内,所以这里求的是 < k
ans -= (1 << i);
else cnt += a[ans];//cnt用来累加比当前ans小的总组数
}
//求出的ans是累加和(即小于等于ans的数的个数)小于k的情况下ans的最大值,所以ans+1就是第k大的数
return ans + 1;
}
void init()
{
int i;
for (i=0;i<M;i++)
{
//lowbit[i]=i&(-i);//初始化会超时
a[i]=0;
}
}
void in(int p)
{
while(p<Max)
{
a[p]+=1;
p+=p&(-p);//lowbit[i]=i&(-i);
}
}
void re(int p)
{
while(p<Max)
{
a[p]-=1;
p+=p&(-p);//lowbit[i]=i&(-i);
}
}
int main()
{
//freopen("a","r",stdin);
int i,j,n,k,r;
while (1)
{
scanf("%d%d",&n,&r);
if (n==0 && r==0) break;
int rr=2*r*r+2*r+1;
//memset(a,0,sizeof(a));
init();
Max=0;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
scanf("%d",&c[i][j]);
c[i][j]+=1;
if (c[i][j]>Max) Max=c[i][j];
}
//(r+1,r+1)
for (i=1;i<=2*r+1;i++)
for (j=1;j<=2*r+1;j++) in(c[i][j]);
for (i=r+1;i<=n-r;i++)
{
if ((i-r)%2!=0)
{
for (j=r+1;j<=n-r;j++)
{
if (j==r+1)
{
if (i==r+1) ;
else
{
for (k=1;k<=2*r+1;k++)
{
re(c[i-r-1][k]);
in(c[i+r][k]);
}
}
}
else
{
for (k=i-r;k<=i+r;k++)
{
re(c[k][j-r-1]);
in(c[k][j+r]);
}
}
c1[i][j]=f_kth(rr);
}
}
else
{
j=n-r;
for (k=j-r;k<=j+r;k++)
{
re(c[i-r-1][k]);
in(c[i+r][k]);
}
c1[i][j]=f_kth(rr);
for (j=n-r-1;j>=r+1;j--)
{
for (k=i-r;k<=i+r;k++)
{
re(c[k][j+r+1]);
in(c[k][j-r]);
}
c1[i][j]=f_kth(rr);
}
}
}
for (i=r+1;i<=n-r;i++)
{
for (j=r+1;j<=n-r;j++) printf("%d ",c1[i][j]-1);
printf("\n");
}
}
return 0;
}